在RecyclerView.ViewHolder

时间:2017-02-13 13:58:30

标签: android android-fragments android-viewholder

我有一个RecyclerView.ViewHolder,它将根据传递的对象的实例将不同的片段添加到其FrameLayout中。问题出在几乎不可能将片段添加到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)

我的猜测是,由于ViewHolder模式,id在某些时候发生冲突,或者视图被破坏了。所以我的问题是。

1)有什么解决方法吗?

2)有没有比添加片段更好的做法。我添加片段的原因是,ViewHolder子项的逻辑都可以位于单个片段中。当然,我可以将片段的两个视图放入ViewHolder xml中。并且只是setVisible()取决于条件。但这只会让我的ViewHolder包含太多逻辑。

如果有人为什么需要片段而感到困惑。这就是我想要实现的目标。 The image

4 个答案:

答案 0 :(得分:4)

简短回答:你不应该在recyclerView中使用碎片,这不是它们的目的。

答案很长:here

答案 1 :(得分:0)

onBindViewHolder:

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

ViewHolder:

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

答案 2 :(得分:0)

您应该确切地知道recyclerview创建了您的持有人并为其绘制了一个视图,因此您需要在适配器的 $("#id_name").click(function (event) { ..//Code }); 方法中附加一个片段。在“附加片段”方法中,应检查片段管理器是否已包含这些片段,以防止创建多个实例。

适配器:

onViewAttachedToWindow

方法实现:

 override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {    
    if(holder is FragmentsHolder){
        attachFragmentToContainer(holder.flContainer)            
    }
    super.onViewAttachedToWindow(holder)
}

这对大量用户进行了测试-没有崩溃,性能很好。

答案 3 :(得分:0)

我遇到了同样的问题,并通过在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

        }
    });