Как восстановить состояние флажка в элементах списка Android RecyclerView при повороте устройства

Мое текущее приложение для Android содержит RecyclerView, у которого есть флажок в каждом элементе списка.

Моя проблема в том, что при повороте экрана флажок всегда возвращается в неотмеченное состояние.

Я храню свои обновленные элементы списка в своей деятельности ViewModel и передаю этот сохраненный список обратно адаптеру в onCreate.

Из моих журналов отладки я вижу, что состояние списка правильно содержит проверенное/непроверенное состояние каждого элемента списка.

Я также вышел из списка в конструкторе адаптера, который также показывает, что проверенное состояние все еще действительно.

однако, когда вызывается onBindViewHolder, все элементы списка не проверяются.

вот мои фрагменты кода:-

  @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_layout);

        manageViewModel();
        recyclerView = findViewById(R.id.my_rv);

        final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
        adapter = new MedicationAdapter(viewModel.getList(), this);
        recyclerView.setAdapter(adapter);

   }



protected void onSaveInstanceState(Bundle state) {
    super.onSaveInstanceState(state);
    viewModel.saveList(adapter.getList());
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
}

Флажок элемента моего списка определяется в xml следующим образом:-

<android.support.v7.widget.AppCompatCheckBox
            android:id="@+id/my_checkbox_header"
            android:layout_width="wrap_content"
            android:saveEnabled="false"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:text="" />

Каков правильный подход к сохранению состояния флажка в элементах RecyclerView при ротации устройства?

Код моего адаптера:-

    public class MusicalAdapter extends RecyclerView.Adapter<MusicalAdapter.ViewHolder> {

        private static final String TAG = "MusicalAdapter";
        private int previousExpandedPosition = -1;
        private int mExpandedPosition = -1;

        private final List<MusicalUI> musicals = new ArrayList<>();
        private final ItemClickListener clickListener;

        MusicalAdapter(final List<MusicalUI> musicals, final ItemClickListener clickListener) {
            this.musicals.clear();
            this.musicals.addAll(musicals);
//AT THIS POINT THE CHECKED VALUES ARE AS EXPECTED

            this.clickListener = clickListener;
        }

        @NonNull
        @Override
        public MusicalAdapter.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
            final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.all_disco_item_x, parent, false);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(@NonNull final MusicalAdapter.ViewHolder holder, final int position) {
            final MusicalUI musical = musicals.get(position);

            Log.d(TAG, "onBindViewHolder() called with: musical = [" + musical.getChecked());

// AT THI SPOINT THE CHECKED VALUES ARE ALWAYS FALSE!!!!!!!!
            final boolean isExpanded = position == mExpandedPosition;


            for (final MusicalUI musicalx : musicals) {
                Log.d(TAG, "onBindViewHolder(): " + musicalx.getChecked());
            }

            // Header
            holder.discoDetailsHeaderLayout.setVisibility(View.VISIBLE);
            holder.musicalNameHeader.setText(musical.getDiscoName());

            holder.discoSelectedHeader.setOnCheckedChangeListener(null);
            holder.discoSelectedHeader.setChecked(musical.getChecked());
            holder.discoSelectedHeader.setOnCheckedChangeListener((buttonView, isChecked) -> musical.setChecked(isChecked));


            if (isExpanded)
                previousExpandedPosition = position;

            holder.itemView.setOnClickListener(v -> {
                mExpandedPosition = isExpanded ? -1 : position;
                notifyItemChanged(previousExpandedPosition);
                notifyItemChanged(position);
            });

        }

        @Override
        public int getItemCount() {
            return musicals.size();
        }


        MusicalUI getItem(final int position) {
            return musicals.get(position);
        }

        void updateList(final List<MusicalUI> newMusicals) {
            final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new GenericDiffUtilCallback<>(this.musicals, newMusicals));
            diffResult.dispatchUpdatesTo(this);

            this.musicals.clear();
            this.musicals.addAll(newMusicals);
        }

        List<MusicalUI> getList() {
            return musicals;
        }

        /**
         *
         */
        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, CompoundButton.OnCheckedChangeListener {
    ...
            }


        }
    }

person Hector    schedule 25.01.2019    source источник
comment
проверьте этот мой ответ stackoverflow.com/a/54103578/7666442, он даст вам подсказку   -  person AskNilesh    schedule 25.01.2019
comment
@NileshRathod, в моем PoJo уже есть логическое поле, это поле установлено правильно, пока я не попытаюсь использовать его в onBindViewHolder, а затем оно всегда ложно. Несмотря на то, что я создал свой адаптер recyclerView с действительным проверенным списком.   -  person Hector    schedule 25.01.2019
comment
поделитесь кодом адаптера с вопросом   -  person AskNilesh    schedule 25.01.2019


Ответы (1)


Он меняется, потому что при изменении поворота ваша деятельность перезапускается. Вы можете либо написать много кода для восстановления своего состояния, или просто избежать перезапуска. Это правильный путь

Чтобы ваша активность не перезапускалась при изменении ротации

в AndroidManifest найдите свою активность и добавьте

android:configChanges="orientation"

Android также рекомендует избегать этого в большинстве случаев.

Он говорит, что пусть андроид сам меняет конфигурацию.

Предупреждение. Самостоятельная обработка изменения конфигурации может значительно затруднить использование альтернативных ресурсов, поскольку система не применяет их автоматически. Этот метод следует рассматривать в качестве крайней меры, когда необходимо избежать перезапусков из-за изменения конфигурации, и он не рекомендуется для большинства приложений.

Чтобы объявить, что ваша активность обрабатывает изменение конфигурации, отредактируйте соответствующий элемент в файле манифеста, включив в него атрибут android:configChanges со значением, представляющим конфигурацию, которую вы хотите обрабатывать. Возможные значения перечислены в документации для атрибута android:configChanges. Наиболее часто используемые значения — «ориентация», «размер экрана» и «скрытая клавиатура». Значение «ориентация» предотвращает перезагрузку при изменении ориентации экрана.

Подробнее

person rgaraisayev    schedule 25.01.2019