Android – обновление ListView при щелчке диалогового окна

Я пробовал это некоторое время, и моя неопытность брала верх надо мной. Любые указатели или предложения о том, как мне следует подходить к проблеме, будут очень признательны.

У меня есть собственный ListView, каждый элемент которого содержит две строки. Один конкретный элемент в ListView меняет режим работы. Чего я пытаюсь добиться, так это:

  1. Щелкнув этот элемент ListView, откройте диалоговое окно, содержащее список, прикрепленный к переключателям.
  2. При выборе одного из элементов диалогового окна закройте диалоговое окно и измените одну из двух строк ListView в этом элементе, чтобы отразить этот выбор режима.

Мои вопросы таковы: как я могу обновить элементы ListView при нажатии кнопки диалога?

Я могу создать ListView и Dialog, но обновление ListView оказывается сложным. Начальные значения могут быть установлены, но не обновляются. Я знаю, что мне нужно вызвать .notifyDataSetChanged, но, поскольку я хотел бы, чтобы это произошло внутри onItemClick для диалогового окна, я получаю сообщение об ошибке: «Невозможно ссылаться на неконечную переменную внутри внутреннего класса, определенного в другом методе. ", и мои переменные не могут быть окончательными.

Что я пробовал:

  • Уведомление об изменении данных непосредственно перед закрытием диалогового окна. Получил ошибку "неконечная переменная".
  • Реализация настройки контроллера представления модели и попытка создать метод, который действует как «onVariableChangeListener», но я оставил эту идею, потому что она казалась немного не по теме, и я не совсем ее понимал.
  • Создайте один метод для вызова диалогового окна и другой для обновления данных ListView. Проблема заключалась в том, что метод Update не ожидал нажатия элемента Dialog. Даже после изменения и повторного открытия диалогового окна ListView не обновляется.
  • Создание метода, работающего аналогично onCreateView, который вызывается при каждом щелчке элемента. Он должен создать и раздуть новый ListView. Поскольку он вызывается в onItemClick, он не имеет ошибки «неконечная переменная», хотя мне потребовалось создать окончательные экземпляры параметров onCreateView. Я не уверен в последствиях, которые это имеет. Это верный подход?

Следующий код представляет собой смесь двух последних идей. Существуют методы для диалога и обновления отдельно, хотя обновление не ждет диалога, и параметры, идущие в метод обновления, являются окончательными.

Я надеюсь, что решение будет простым, но я считаю, что на работе есть несколько ошибок. Я знаю, что SO любит задавать вопросы, которые могут относиться к другим, кто может прочитать это позже, поэтому я прошу прощения, если это немного специфично для моего случая. Любая помощь приветствуется!

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;
        }

person clb9355    schedule 11.07.2014    source источник


Ответы (3)


Я предлагаю вам создать отдельный DialogFragment для отображения элементов режима и передать выбранный элемент в ваш CalibrationFragment.

Во-первых, прочитайте http://developer.android.com/training/basics/fragments/communicating.html.

Создайте DialogFragment и внутри него напишите Listener с методом обратного вызова, чтобы сообщить о выбранном элементе в диалоговом окне. Затем внедрите этот прослушиватель в свой CalibrationFragment и в обратном вызове установите элемент в данных списка и обновите адаптер списка.

person Timuçin    schedule 11.07.2014
comment
Мне придется прочитать о методах обратного вызова, но просто чтобы убедиться, что я понимаю процесс, вы говорите, что я должен (1) написать фрагмент, который является дочерним элементом моего CalibrationFragment.java, (2) когда я нажимаю ListItem, откройте DialogFragment, который также откроет мой Dialog, (3) когда щелкнут элемент Dialog, используйте метод обратного вызова, чтобы передать информацию обратно в CalibrationFragment и внести там изменения? - person clb9355; 11.07.2014
comment
(1) DialogFragment, который вы напишете, не должен быть дочерним элементом CalibrationFragment. Это должен быть DialogFragment сам по себе. (2) Да, прочитайте документацию DialogFragment. (3) Правильно. - person Timuçin; 11.07.2014

Вы должны удалить

updateData(finalInflater, finalContainer, finalSavedInstanceState);

строка из onitemclick

и добавить в showdialog() в событии onclick

может быть работа

person Ashish Pedhadiya    schedule 11.07.2014
comment
Вы хотите вызвать updateData из события onClick showDialog? Не повезло, хотя это заставляет код ждать, пока что-то внутри диалога не будет выбрано, что решает эту часть. Однако ListView по-прежнему не обновляется. - person clb9355; 11.07.2014

Вам просто нужно обновить ArrayList<DataItem> data arrayList при нажатии кнопки ОК в диалоговом окне с соответствующим выбранным значением. После этого сразу же в том же событии клика (кнопка «Диалог ok») просто уведомите свой ListView как myList.notifyDataSetChanged(); об активности, откуда был создан диалог. Надеюсь, это поможет вам...

person naran z    schedule 11.07.2014