片段getChildFragmentManager.executePendingTransactions()错误:找不到视图

时间:2015-09-22 15:05:56

标签: android android-fragments android-recyclerview fragmentmanager

当你打开我的应用程序时,我首先让一个viewpager在顶部有各种标签,你可以点击它们,每个标签显示不同的片段。

在片段中称为" TEST"是一个回收者视图,其中recyclerview中的每个项目都是子片段。

test

在recyclerview中,每个片段的顶部都有一些按钮,因此如果单击地图按钮,片段可以更改为显示地图等的另一个片段。

在我的recyclerview适配器中,我给下面的xml(example.xml)充气,它代表了recyclerview的每一行:

<?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/groupholder"
        android:background="#FFF">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/fragment_container">
        </RelativeLayout>

    </RelativeLayout>

fragment_container用于保存膨胀的片段。

以下是RecyclerView.Adapter类中用于填充recyclerview的相关部分:

 //the view holder class
class ExampleViewHolder extends RecyclerView.ViewHolder {

    RelativeLayout fragmentContainer;

    public ExampleViewHolder(View view) {
        super(view);
        //we are creating a framecontainer for the fragment
        fragmentContainer = (RelativeLayout) view.findViewById(R.id.fragment_container);
        }   

}

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //inflating the layout that contains the fragment for the ExampleViewHolder
        v = LayoutInflater.from(parent.getContext()).inflate(R.layout.example, parent, false);
    }


    @Override
    public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
    if (holder instanceOf ExampleViewHolder) {


        //The "f" below is the fragment that gets past into this Recycler.Adapter through the adapter's constructor.
         f.getChildFragmentManager().beginTransaction().add(((ExampleViewHolder) holder).fragmentContainer.getId(), new PlaceImageFragment()).commit();
        //this must execute immediately.
        //This is the part that crashes the app
        f.getChildFragmentManager().executePendingTransactions();
        }

    }

由于commit命令被安排在进程的主线程(http://developer.android.com/reference/android/app/FragmentManager.html#executePendingTransactions())上异步执行,我必须调用executePendingTransactions()来让fragmentmanager立即执行命令。

如果我没有调用executePendingTransactions(),应用程序可以运行,但片段不会立即填充,我也可以在屏幕上看到,因为片段的填充速度非常慢或在某些情况下根本没有。

但是,如果我确实调用了executePendingTransactions(),那么应用程序会崩溃并显示行executePendingTransactions()就是应用程序崩溃的原因:

  

java.lang.IllegalArgumentException:找不到id 0x7f0f0096的视图   (com.example.simon:ID / fragment_container)   片段PlaceImageFragment {52e819f8#0 id = 0x7f0f0096}

我有什么想法可以让它发挥作用吗?

修改

我认为这给我一个没有查看的原因是getChildFragmentManager在父片段布局xml中查找id / fragment_container,但它不在那里,因为父片段只包含recyclelerview in xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_height="match_parent"
    android:id="@+id/main_recyclerview_holder">
<!--The padding here creates the space at the top of the ad-->
    <android.support.v7.widget.RecyclerView
        android:id="@+id/main_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
/>

</RelativeLayout>

1 个答案:

答案 0 :(得分:0)

尝试在onBidViewHolder()中更改片段,并使用recyclerViewAdapter.notifyItemChanged(position)启动它。如果您将逻辑从片段更改为getItemViewType(),那将是更好的解决方案。

编辑:

当您尝试在动态创建的视图上设置片段时,问题就开始了,当您调用executePendingTransactions()时,仍然没有视图(View对象已创建但仍未在屏幕上显示)此问题可通过以下方式解决:

((ExampleViewHolder) holder).fragmentContainer.post(new Runnable() {
            @Override
            public void run() {
                f.getChildFragmentManager().executePendingTransactions();
            }
        });

所以只有在创建视图时才会调用此代码。 但是你仍然有问题,因为所有的recyclerView项都有相同的id,你可以通过以下方式避免这种情况:

int i = ((ExampleViewHolder) holder).fragmentContainer.generateViewId();
        ((ExampleViewHolder) holder).fragmentContainer.setId(i);

        f.getChildFragmentManager().beginTransaction().add(i, new PlaceImageFragment()).commit();

但此代码只能从API级别17开始工作。 或者您可以创建自己的静态ID(糟糕的解决方案)。

我仍然看不到使用getItemViewType()逻辑的问题 - 您可以创建3个不同的视图类型,其中包含按钮的副本,这些按钮将是不同的对象,但它们将调用相同的onClickListeners。

有关动态创建的视图和片段的更多信息,请参阅: How do I add a Fragment to an Activity with a programmatically created content view