2

I have been trying this for a while now and my inexperience has been getting the best of me. Any pointers or suggestions about how I should be approaching the issue will be greatly appreciated.

I have a custom ListView with each item containing two strings. One particular item in the ListView is changing a mode of operation. What I am trying to achieve is this:

  1. On clicking this ListView item, open a Dialog containing a list attached to radio buttons.
  2. On selecting one of the Dialog items, close the Dialog and change one of the two ListView strings in that item to reflect that mode selection.

My questions is this: How can I update my ListView items when a Dialog button is clicked?

I can create the ListView and Dialog fine, but updating the ListView is proving difficult. Initial values can be set but are not being updated. I know that I need to call .notifyDataSetChanged, but as I would like this to happen inside onItemClick for the Dialog, I get an error along the lines of "Cannot refer to a non-final variable inside an inner class defined in a different method", and my variables cannot be final.

What I have tried:

  • Notifying the data change immediately before the dialog closes. Got "non-final variable" error.
  • Implementing a model-view-controller setup and trying to create a method that acts like an "onVariableChangeListener", but I left this idea because it seemed a bit off-topic and I wasn't quite understanding it.
  • Create one method to bring up the Dialog and another to update the ListView data. The issue was that the Update method was not waiting for the Dialog item to be clicked. Even after the dialog selection is changed and re-opened, the ListView is not updated.
  • Creating a method, operating similarly to onCreateView, that is called whenever the item is clicked. It should create and inflate a new ListView. Since it is called within onItemClick it does not have the "non-final variable" error, though it required me to create final instances of onCreateView's parameters. I am unsure of the implications this has. Is this a valid approach?

The following code is a mix of the latter two ideas. There are methods for the Dialog and update separately, though updating does not wait for the dialog and the parameters going into the update method are final.

I am hoping the solution will be straightforward, but I believe there are multiple errors at work. I know SO likes to have questions that can apply to others who may read this later on, so I apologise if this is a bit specific to my case. Any help is appreciated!

CalibrationFragment.java

public class CalibrationFragment extends Fragment{
    private Context mContext;
    private ArrayList<DataItem> data = new ArrayList<DataItem>(); // DataItem is a class that sets two strings
    private ArrayList<DataItem> currentData = new ArrayList<DataItem>(); // Two records kept to identify changes
    ListView myList;
    int checkedItem1 = 0; // For the dialog boxes.

    @Override
    public void onCreate (Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        mContext = getActivity(); // Get the context of the Activity and therefore the fragment
        myList = new ListView (mContext); // Create a ListView

        // Set initial values
        calibrationData readData = new calibrationData(); // readData will contain all ListView values
        // ... other items...
        readData.setMode(checkedItem1, mContext); // Set to 0, 1 or 2 indicating different modes
        // ... other items...

        // Create elements to be added to the list
        // ...
        DataItem calibration4 = new DataItem(getResources().getString(R.string.mode_calibration), readData.getMode());
        // readData.getMode() returns different strings depending on int input
        // ...

        // Add elements to the list
        // ...
        data.add(calibration4);
        // ...

        currentData = data; // Initialise both as the same
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        // Inflate the view
        View rootView = inflater.inflate(R.layout.fragment_list, container, false);
        myList=(ListView) rootView.findViewById(android.R.id.list);
        // Create and set the customised adapter to take data (ArrayList<DataItem>) and format
        // each element as defined in list_row.xml
        CustomAdapter adapter = new CustomAdapter(mContext, R.layout.list_row, data);
        myList.setAdapter(adapter);
        // The above adapter is the one I need to notify            

        // For the sake of letting my code compile in onItemClick. Unsure if this causes further issues.
        final LayoutInflater finalInflater = inflater;
        final ViewGroup finalContainer = container;
        final Bundle finalSavedInstanceState = savedInstanceState;

        // CustomAdapter adapter cannot be used in setOnItemClickListener because it is non-final
        myList.setOnItemClickListener(new AdapterView.OnItemClickListener()
        {
            public void onItemClick(AdapterView<?> parentAdapter, View view, int position, long id)
            {
                switch((int)id){
                // [Different cases here]

                case 3: // Clicks of Mode item
                    // Creates Dialog
                    showDialog((int)id, checkedItem1);
                    // updateData executes as Dialog is generated, not clicked or closed. Do not want this.
                    updateData(finalInflater, finalContainer, finalSavedInstanceState);
                break;

                // [Rest of the cases and default statement here]
                }
            }
        });

        return rootView; // onCreateView must return a View variable if displaying a UI.
    }

    public void showDialog(int id, int checkedItem)
    {
        // In case I want to have other dialogs later, ensure this is for Mode selection.
        if(id == 3){
            final CharSequence[] modeItems = {
                    "Mode 1", "Mode 2", "Mode 3"
            }; // For Dialog
            AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
            builder.setTitle(getResources().getString(R.string.mode_calibration));
            builder.setSingleChoiceItems(modeItems, checkedItem, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int item) {
                    checkedItem1 = item; // Change checkedItem1 to the index selected in the dialog
                    calibrationData readData = new calibrationData();
                    readData.setMode(checkedItem1, mContext); // Set Mode depending on checkedItem
                     // Create DataItem representing new mode
                    DataItem newMode = new DataItem(getResources().getString(R.string.mode_calibration), readData.getMode());
                    currentData.set(3, newMode); // Set new mode into currentData.
                    // Eventual comparison with var 'data' will indicate a change

                    dialog.dismiss();                       
                }
            });
            AlertDialog alert = builder.create();
            alert.show();   
        }

        public View updateData(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){

            // Inflate the new view
            View rootView = inflater.inflate(R.layout.fragment_list, container, false);
            myList=(ListView) rootView.findViewById(android.R.id.list);
            // Create and set the customised adapter to take data (ArrayList<DataItem>) and format
            // each element as defined in list_row.xml
            CustomAdapter adapter = new CustomAdapter(mContext, R.layout.list_row, data);
            myList.setAdapter(adapter);

            // As this is only called in onClick, I can work with data assuming something has changed and been clicked.
            int i = 0;
            // Compare each element inside data and currentData.
            for(i = 0; i < data.size(); i++){
                if(data.get(i) != currentData.get(i)) data = currentData;
                if(i==5) Toast.makeText(mContext, "Iterating to end", Toast.LENGTH_SHORT).show(); // debug purposes
            }
            adapter.notifyDataSetChanged(); // Update list

            return rootView;
        }
clb9355
  • 289
  • 4
  • 16

3 Answers3

0

You have to remove

updateData(finalInflater, finalContainer, finalSavedInstanceState);

line from onitemclick

and add to showdialog() in onclick event

may be work

  • Do you mean to call updateData from inside showDialog's onClick event? No luck, although it DOES force the code to wait until something inside the dialog has been selected, which solves that part. The ListView still does not update, however. – clb9355 Jul 11 '14 at 06:44
0

You just have to update ArrayList<DataItem> data arrayList on click event of your dialog ok button with appropriate selected value. After that immediately in the same click event(Dialog ok button) just notify your ListView like myList.notifyDataSetChanged(); of activity from where the dialog was generated. Hope this helps you...

naran z
  • 486
  • 3
  • 13
0

I suggest you to create a separate DialogFragment to show the modeItems and pass the selected item to your CalibrationFragment.

First, read http://developer.android.com/training/basics/fragments/communicating.html.

Create a DialogFragment and inside it write a Listener with a callback method to inform selected item in the dialog. Then, implement this Listener in your CalibrationFragment and in the callback, set the item on the list data and update the list adapter.

Timuçin
  • 4,653
  • 3
  • 25
  • 34
  • I will have to read up on callback methods, but just to verify that I'm understanding the process, you're saying I should (1) write a fragment that is a child of my CalibrationFragment.java, (2) when I click a ListItem, open DialogFragment which will also open my Dialog, (3) when a Dialog item is clicked, use the callback method to feed information back to CalibrationFragment and make the changes there? – clb9355 Jul 11 '14 at 07:15
  • 1
    (1) The DialogFragment that you will write should not be a child of CalibrationFragment. It must be a DialogFragment on its own. (2) Yes, read about DialogFragment documentation. (3) Correct. – Timuçin Jul 11 '14 at 07:18