web-dev-qa-db-ja.com

RecyclerView.ViewHolderにフラグメントを追加する

渡されたオブジェクトのインスタンスに基づいて、FrameLayoutに異なるフラグメントを追加するRecyclerView.ViewHolderがあります。問題は、ViewHolderにフラグメントを追加することがほぼ不可能である場合に発生します。親からFragmentManagerをすでに渡したことに注意してください。最初は私はこのコードで試します

public void setSomething(boolean A) {
    if (A) {
         mFragmentManager.beginTransaction()
            .replace(mBinding.typeContainerLayout.getId(), new FragmentA())
            .commit();
    } else {
        mFragmentManager.beginTransaction()
            .replace(mBinding.typeContainerLayout.getId(), new FragmentB())
            .commit();
    }
}

このコードの問題は、すべてのViewHolderが同じIDを共有するため、単一のViewHolderのみがフラグメントを追加できることです。私のRecyclerViewでは、最初のセルのみがフラグメントを追加しました。この問題に取り組むために、別のFrameLayoutを作成してtypeContainerLayoutに追加します。今私のコードはこのようになります。

public void setSomething(boolean A) {
    FrameLayout frameLayout = new FrameLayout(mContext);
    frameLayout.setId(View.generateViewId());
    mBinding.typeContainerLayout.removeAllViews();
    mBinding.typeContainerLayout.addView(frameLayout)

    if (A) {
         mFragmentManager.beginTransaction()
            .replace(frameLayout.getId(), new FragmentA())
            .commit();
    } else {
        mFragmentManager.beginTransaction()
            .replace(frameLayout.getId(), new FragmentB())
            .commit();
    }
}

これで、各ViewHolderはフラグメントを正しく追加し、独自のフラグメントを持っています。しかし、5 ViewHolderのように追加してRecyclerViewを下にスクロールしようとすると、問題が発生します。

Java.lang.IllegalArgumentException: No view found for id 0x4 (unknown) for fragment FragmentA{7c55a69 #0 id=0x4 FragmentA}
                      at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1292)
                      at Android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(FragmentManager.Java:2323)
                      at Android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.Java:2136)
                      at Android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.Java:2092)
                      at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:1998)
                      at Android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.Java:709)
                      at Android.os.Handler.handleCallback(Handler.Java:739)
                      at Android.os.Handler.dispatchMessage(Handler.Java:95)
                      at Android.os.Looper.loop(Looper.Java:148)
                      at Android.app.ActivityThread.main(ActivityThread.Java:5417)
                      at Java.lang.reflect.Method.invoke(Native Method)
                      at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:726)
                      at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:616)

私の推測では、ある時点でIDが競合したか、またはViewHolderパターンが原因でビューが破壊されたと考えられます。だから私の質問はそれです。

1)回避策はありますか?

2)フラグメントを追加するよりも良い方法はありますか?フラグメントを追加する理由は、ViewHolderのサブ項目のロジックをすべて1つのフラグメントに配置できるようにするためです。もちろん、フラグメントの両方のビューをViewHolder xmlに入れるだけです。そして、状況に応じてsetVisible()を実行します。しかし、それは私のViewHolderに含まれているロジックが多すぎることになります。

フラグメントが必要な理由が混乱している場合。これは私が達成しようとしていることです。 画像

13
Ginsan

私は同じ問題に直面し、onBindViewHolderコールバックでaddOnChildAttachStateChangeListener RecyclerViewコールバックを使用して解決しました。

listView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
        @Override
        public void onChildViewAttachedToWindow(@NotNull View view) {
            //Create your fragment container here using the view param and add your fragment to the container
        }

        @Override
        public void onChildViewDetachedFromWindow(@NotNull View view) {
            //Destroy the fragment container here

        }
    });
1
Vincent Gachet

onBindViewHolder:

yourFragment fragment = new yourFragment();
    try {
        viewHolder.Fragment(fragment);
    }catch (Exception e){
        Toast.makeText(context, "BindViewHolder"+e.getMessage(), Toast.LENGTH_SHORT).show();
    }

ビューホルダー:

class ViewHolder extends RecyclerView.ViewHolder {
    TextView name;
    FrameLayout container;

    private ViewHolder(@NonNull View itemView) {
        super(itemView);

        container = itemView.findViewById(R.id.fragmentContainer);
    }

    private void Fragment(final Fragment fragment) {
        FragmentTransaction transaction = ((AppCompatActivity) context).getSupportFragmentManager()
                .beginTransaction();
        try {
            transaction.add(R.id.fragmentContainer, fragment)
                    .commit();
        } catch (Exception e) {
            Toast.makeText(context, "ViewHolder " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }
}
0
MazharulSabbir