1. ホーム
  2. android

[解決済み] Android RecyclerView : notifyDataSetChanged() IllegalStateException

2022-06-18 14:32:30

質問

notifyDataSetChanged()を使って、recycleviewの項目を更新しようとしています。

これは、recycleviewアダプタのonBindViewHolder()メソッドです。

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {

     //checkbox view listener
    viewHolder.getCheckbox().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

            //update list items
            notifyDataSetChanged();
        }
    });
}

私がしたいことは、チェックボックスをチェックした後、リストアイテムを更新することです。しかし、私は不正な例外を取得します。 "Cannot call this method while RecyclerView is computing a layout or scrolling"

java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling
    at android.support.v7.widget.RecyclerView.assertNotInLayoutOrScroll(RecyclerView.java:1462)
    at android.support.v7.widget.RecyclerView$RecyclerViewDataObserver.onChanged(RecyclerView.java:2982)
    at android.support.v7.widget.RecyclerView$AdapterDataObservable.notifyChanged(RecyclerView.java:7493)
    at android.support.v7.widget.RecyclerView$Adapter.notifyDataSetChanged(RecyclerView.java:4338)
    at com.app.myapp.screens.RecycleAdapter.onRowSelect(RecycleAdapter.java:111)

notifyItemChanged()も使ってみましたが、同じ例外です。何かが変更されたことをアダプタに通知するために、何か秘密の更新方法がありますか?

どのように解決するのですか?

setOnCheckedChangeListener()メソッドをアダプタの内部クラスであるViewHolderに移動してください。

onBindViewHolder() は初期化するメソッドではありません。 ViewHolder . このメソッドは、各リサイクラーアイテムをリフレッシュするためのステップです。 を呼び出すと notifyDataSetChanged() , onBindViewHolder() が呼び出されます。

ですから、もし notifyDataSetChanged() に入れる。 onCheckChanged() でチェックボックスを初期化し onBindViewHolder() で初期化すると、循環的なメソッド呼び出しのため、IllegalStateExceptionが発生します。

click checkbox -> onCheckedChanged() -> notifyDataSetChanged() -> onBindViewHolder() -> set checkbox -> onChecked...

単純に、Adapterにフラグを一つ入れれば解決します。

これを試してみてください。

private boolean onBind;

public ViewHolder(View itemView) {
    super(itemView);
    mCheckBox = (CheckBox) itemView.findViewById(R.id.checkboxId);
    mCheckBox.setOnCheckChangeListener(this);
}

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    if(!onBind) {
        // your process when checkBox changed
        // ...

        notifyDataSetChanged();
    }
}

...

@Override
public void onBindViewHolder(YourAdapter.ViewHolder viewHolder, int position) {
    // process other views 
    // ...

    onBind = true;
    viewHolder.mCheckBox.setChecked(trueOrFalse);
    onBind = false;
}