Search code examples
androidandroid-fragmentsandroid-listviewandroid-dialogfragmentandroid-contextmenu

Fragment ListView ContextMenu with AlertDialog


I have a ListView that is within a Fragment. The ListView has a ContextMenu to edit and delete entries. I am trying to set a DialogFragment to launch on selection of the EDIT option of my ContextMenu, however nothing is being displayed when edit is chosen. Is this a view problem? Thanks in advance.

Original Post:

public static class FragmentS extends Fragment {

    private ListView saveListView;
    private List<LiftSave> LiftSaves = new ArrayList<LiftSave>();
    private static final int EDIT = 0, DELETE = 1;

    LiftSave longClickedItemLiftSave;
    DatabaseHandler dbHandler;
    ArrayAdapter<LiftSave> saveAdapter;


    public FragmentS() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.listview_s,
                container, false);
        saveListView = (ListView) rootView.findViewById(R.id.saveListView);
        registerForContextMenu(saveListView);
        DatabaseHandler dbHandler;
        dbHandler = new DatabaseHandler (getActivity().getApplicationContext());
        if (dbHandler.getLiftSavesCount() != 0)
            LiftSaves.addAll(dbHandler.getAllLiftSaves());

        populateList();

        saveListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                longClickedItemLiftSave = (LiftSave) parent.getItemAtPosition(position);
                return false;
            }
        });

        return rootView;
    }

    private void populateList() {
        saveAdapter = new SaveListAdapter();
        saveListView.setAdapter(saveAdapter);
    }


    public class SaveListAdapter extends ArrayAdapter<LiftSave> {
            public SaveListAdapter() {
                super(getActivity(), R.layout.listview_item, LiftSaves);
            }

            @Override
            public View getView(int position, View view, ViewGroup parent) {
                if (view == null)
                    view = getActivity().getLayoutInflater().inflate(R.layout.listview_item, parent, false);

                LiftSave currentLiftSave = LiftSaves.get(position);

                TextView liftName = (TextView) view.findViewById(R.id.liftName);
                liftName.setText(currentLiftSave.getLiftName());
                TextView maxValue = (TextView) view.findViewById(R.id.maxValue);
                maxValue.setText(currentLiftSave.getMaxValue());
                TextView weightAndReps = (TextView) view.findViewById(R.id.weightAndReps);
                weightAndReps.setText(currentLiftSave.getRepsAndWeight());
                TextView liftNotes = (TextView) view.findViewById(R.id.liftNotes);
                liftNotes.setText(currentLiftSave.getLiftNotes());
                TextView date = (TextView) view.findViewById(R.id.todayDate);
                date.setText(currentLiftSave.getTodayDate());

                return view;
            }

    }
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, view, menuInfo);

        menu.setHeaderIcon(R.drawable.pencil_icon);
        menu.setHeaderTitle("Save Options");
        menu.add(Menu.NONE, EDIT, menu.NONE, "Edit Save");
        menu.add(Menu.NONE, DELETE, menu.NONE, "Delete Save");
    }

    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case EDIT:
                // TODO: Add save edit code
                break;
            case DELETE:
             AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
                builder.setMessage("Are you sure you want to delete?")
                        .setCancelable(false)
                        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dbHandler = new DatabaseHandler(getActivity().getApplicationContext());
                                dbHandler.deleteLiftSave(longClickedItemLiftSave);
                                saveAdapter.remove(longClickedItemLiftSave);
                            }
                        })
                        .setNegativeButton("No", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        });

                break;
                            }
                            return super.
                            onContextItemSelected(item);
                        }
        }

Updated from Suggestions:

    public static class FragmentS extends Fragment {

    private ListView saveListView;
    private List<LiftSave> LiftSaves = new ArrayList<LiftSave>();
    private static final int EDIT = 0, DELETE = 1;

    LiftSave longClickedItemLiftSave;
    DatabaseHandler dbHandler;
    ArrayAdapter<LiftSave> saveAdapter;


    public FragmentS() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.listview_s,
                container, false);
        saveListView = (ListView) rootView.findViewById(R.id.saveListView);
        registerForContextMenu(saveListView);
        DatabaseHandler dbHandler;
        dbHandler = new DatabaseHandler (getActivity().getApplicationContext());
        if (dbHandler.getLiftSavesCount() != 0)
            LiftSaves.addAll(dbHandler.getAllLiftSaves());

        populateList();

        saveListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
                longClickedItemLiftSave = (LiftSave) parent.getItemAtPosition(position);
                return false;
            }
        });

        return rootView;
    }

    private void populateList() {
        saveAdapter = new SaveListAdapter();
        saveListView.setAdapter(saveAdapter);
    }


    public class SaveListAdapter extends ArrayAdapter<LiftSave> {
            public SaveListAdapter() {
                super(getActivity(), R.layout.listview_item, LiftSaves);
            }

            @Override
            public View getView(int position, View view, ViewGroup parent) {
                if (view == null)
                    view = getActivity().getLayoutInflater().inflate(R.layout.listview_item, parent, false);

                LiftSave currentLiftSave = LiftSaves.get(position);

                TextView liftName = (TextView) view.findViewById(R.id.liftName);
                liftName.setText(currentLiftSave.getLiftName());
                TextView maxValue = (TextView) view.findViewById(R.id.maxValue);
                maxValue.setText(currentLiftSave.getMaxValue());
                TextView weightAndReps = (TextView) view.findViewById(R.id.weightAndReps);
                weightAndReps.setText(currentLiftSave.getRepsAndWeight());
                TextView liftNotes = (TextView) view.findViewById(R.id.liftNotes);
                liftNotes.setText(currentLiftSave.getLiftNotes());
                TextView date = (TextView) view.findViewById(R.id.todayDate);
                date.setText(currentLiftSave.getTodayDate());

                return view;
            }

    }
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, view, menuInfo);

        menu.setHeaderIcon(R.drawable.pencil_icon);
        menu.setHeaderTitle("Save Options");
        menu.add(Menu.NONE, EDIT, menu.NONE, "Edit Save");
        menu.add(Menu.NONE, DELETE, menu.NONE, "Delete Save");
    }

    public boolean onContextItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case EDIT:
                // TODO: Add save edit code

                Context thisContext = getActivity().getBaseContext();
                View dialogViewEdit = LayoutInflater.from(thisContext).inflate(R.layout.edit_save, null, false);
                final EditText editName = (EditText) dialogViewEdit.findViewById(R.id.editLiftName);
                AlertDialog.Builder builderE = new AlertDialog.Builder(this.getActivity());
                AlertDialog dialog = builderE.create();
                builderE.setView(dialogViewEdit);
                dialog.show();
                break;
            case DELETE: //WORKING!
                AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
                builder.setMessage("Are you sure you want to delete this save?")
                        .setCancelable(false)
                        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dbHandler = new DatabaseHandler(getActivity().getApplicationContext());
                                dbHandler.deleteLiftSave(longClickedItemLiftSave);
                                saveAdapter.remove(longClickedItemLiftSave);
                            }
                        })
                        .setNegativeButton("No", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.cancel();
                            }
                        });
                AlertDialog dialogD = builder.create();
                dialogD.show();


                break;
                            }
                            return super.
                            onContextItemSelected(item);
                        }
        }

The EDIT option reflects a custom view from an XML Layout. On selection it shows android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application. Pointing to the line dialog.show();. Such was resolved by calling Context thisContext = getActivity().getBaseContext(); as the the Context for the LayoutInflater. However while no error takes place, the screen simply darkens as though a Dialog was launched, but nothing appears. The DELETE option when selected correctly launches and functions by calling new AlertDialog.Builder(this.getActivity());. Yet, this.getActivity() yields the same result when used in place of thisContext for the EDIT option. Any suggestions would be greatly appreciated.


Solution

  • You still need to display the dialog after the builder setup, like:

    AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity());
    ...
    
    .setNegativeButton("No", new DialogInterface.OnClickListener() {
       public void onClick(DialogInterface dialog, int id) {
                                    dialog.cancel();
       }
     });
    
     // Create the AlertDialog
     AlertDialog dialog = builder.create();
     dialog.show();
    

    It is also a good idea to set and control your own views, like:

    Context thisContext = this.getActivity().getBaseContext();
    
    View dialogView = LayoutInflater.from(thisContext).inflate(R.layout.dialog_edit_1, null, false);
    final EditText editName = (EditText) dialogView.findViewById(R.id.editName);
    
    builder.setView(dialogView);
    

    If you have a problem with getting the correct context, and it seems you do. Code sample:

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) { 
       thisContext = view.getContext();
    }
    

    Notes:

    • Since the DELETE option is in a nested class, using this object in this.getActivity() seems necessary, oddly.
    • The code AlertDialog dialog = builder.create() should be placed after buttons setting, like in sample code.
    • I do setView() before setPositiveButton call.
    • editName is the variable to get a user selected name, as an example.
    • Try dialog.show() first since that is required.
    • There's a good Google webpage @ Dialogs, search for "Adding buttons".