如何在设备旋转的Android RecyclerView列表项中恢复复选框状态

时间:2019-01-25 09:01:56

标签: android android-recyclerview android-checkbox android-viewmodel

我当前的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 {
    ...
            }


        }
    }

1 个答案:

答案 0 :(得分:1)

它会更改,因为更改了轮播后,您的活动会重新开始。您可以编写很多代码来恢复状态 ,也可以避免重新启动。这是正确的方法

要使您的活动不会轮换更改重新开始

在AndroidManifest中找到您的活动并添加

android:configChanges="orientation"

Android还建议在大多数情况下避免使用

它说让android处理配置本身的变化

  

警告:自己处理配置更改可能会做很多事情   更难使用替代资源,因为系统确实   不会自动为您应用它们。这种技术应该是   当您必须避免由于   配置更改,不建议在大多数应用中使用。

     

要声明您的活动已处理配置更改,请编辑   清单文件中的适当元素,以包括   android:configChanges属性,其值表示   您要处理的配置。可能的值列在   android:configChanges属性的文档。最多   常用的值是“方向”,“ screenSize”和   “键盘隐藏”。 “方向”值可防止在   屏幕方向改变。

More Info