【问题标题】:Android Nested Fragments with a RecyclerView带有 RecyclerView 的 Android 嵌套片段
【发布时间】:2017-03-20 15:59:40
【问题描述】:

我有一个包含嵌套片段的项目 (https://github.com/checklist/NestedFragmentsRecycler)。 FragmentA 在 MainActivity 中,包含带有适配器的 RecyclerView。适配器中的每个项目都将返回 FragmentB。由于我需要提供一个用于将 FragmentB 加载到位置的 ID,并且它必须是唯一的,因此我正在生成自己的 ID。第一个片段显示得很好,但不幸的是,当我开始滚动时,我得到一个异常,即找不到我的唯一 ID:

W/ResourceType:获取资源名称时没有包标识符 编号 0x00000004 E/FragmentManager:未找到 id 0x4 的视图 (未知)片段 FragmentB{30cad9b #3 id=0x4} E/FragmentManager: 活动状态:D/FragmentManager:本地FragmentActivity 6d29cb6 状态:D/FragmentManager:mCreated=truemResumed=true mStopped=false mReallyStopped=false D/FragmentManager:
mLoadersStarted=true D/FragmentManager:a2d5538 中的活动片段: D/FragmentManager: #0: FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager: mFragmentId=#7f0b0056 mContainerId=#7f0b0056 mTag=null D/FragmentManager: mState=5 mIndex=0 mWho=android:fragment:0 mBackStackNesting=0 D/FragmentManager:
mAdded=true mRemoving=false mFromLayout=false mInLayout=false D/FragmentManager: mHidden=false mDetached=false mMenuVisible=true mHasMenu=false D/FragmentManager:
mRetainInstance=false mRetaining=false mUserVisibleHint=true D/FragmentManager:mFragmentManager=FragmentManager{a2d5538 in HostCallbacks{327ba76}} D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:mArguments=Bundle[{}] D/FragmentManager:
mContainer=android.widget.FrameLayout{ffe8877 V.E...... ........ 128,32-2432,1496 #7f0b0056 app:id/fragmentA} D/FragmentManager:
mView=android.widget.LinearLayout{ffe8ce4 V.E...... ........ 0,0-2304,1464} D/FragmentManager:
mInnerView=android.widget.LinearLayout{ffe8ce4 V.E...... ........ 0,0-2304,1464} D/FragmentManager:子 FragmentManager{aa7a54d 在 FragmentA{6948911}}:D/FragmentManager:活动片段 aa7a54d: D/FragmentManager: #0: FragmentB{44d0802 #0 id=0x1} D/FragmentManager: mFragmentId=#1 mContainerId=#1 mTag=null D/FragmentManager: mState=5 mIndex=0 mWho=android:fragment:0:0 mBackStackNesting=0 D/FragmentManager:
mAdded=true mRemoving=false mFromLayout=false mInLayout=false D/FragmentManager: mHidden=false mDetached=false mMenuVisible=true mHasMenu=false D/FragmentManager:
mRetainInstance=false mRetaining=false mUserVisibleHint=true D/FragmentManager:
mFragmentManager=FragmentManager{aa7a54d in FragmentA{6948911}} D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:mParentFragment=FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager:
mArguments=Bundle[{TEXT=这是片段 B:0}] D/FragmentManager:
mContainer=android.widget.FrameLayout{c93513 V.E...... ........ 0,0-800,1464 #1} D/FragmentManager:
mView=android.widget.LinearLayout{3899350 V.E...... ........ 0,0-800,1464} D/FragmentManager:
mInnerView=android.widget.LinearLayout{3899350 V.E...... ........ 0,0-800,1464} D/FragmentManager:孩子 FragmentManager{c564949 in FragmentB{44d0802}}:D/FragmentManager:
FragmentManager 杂项状态:D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:
mContainer=android.support.v4.app.Fragment$1@287a24e D/FragmentManager:mParent=FragmentB{44d0802 #0 id=0x1} D/FragmentManager: mCurState=5 mStateSaved=false mDestroyed=false D/FragmentManager: #1: FragmentB{d880f6f #1 id=0x2} D/FragmentManager:
mFragmentId=#2 mContainerId=#2 mTag=null D/FragmentManager:
mState=5 mIndex=1 mWho=android:fragment:0:1 mBackStackNesting=0 D/FragmentManager: mAdded=true mRemoving=false mFromLayout=false mInLayout=false D/FragmentManager:
mHidden=false mDetached=false mMenuVisible=true mHasMenu=false D/FragmentManager: mRetainInstance=false mRetaining=false mUserVisibleHint=true D/FragmentManager:
mFragmentManager=FragmentManager{aa7a54d in FragmentA{6948911}} D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:mParentFragment=FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager:
mArguments=Bundle[{TEXT=这是片段 B:1}] D/FragmentManager:
mContainer=android.widget.FrameLayout{67c947c V.E............ 0,0-800,1464 #2} D/FragmentManager:
mView=android.widget.LinearLayout{c313105 V.E...... ........ 0,0-800,1464} D/FragmentManager:
mInnerView=android.widget.LinearLayout{c313105 V.E...... ........ 0,0-800,1464} D/FragmentManager:孩子 FragmentManager{cbf955a in FragmentB{d880f6f}}:D/FragmentManager:
FragmentManager 杂项状态:D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:
mContainer=android.support.v4.app.Fragment$1@ab0338b D/FragmentManager: mParent=FragmentB{d880f6f #1 id=0x2} D/FragmentManager: mCurState=5 mStateSaved=false mDestroyed=false D/FragmentManager: #2: FragmentB{53c7c68 #2 id=0x3} D/FragmentManager:
mFragmentId=#3 mContainerId=#3 mTag=null D/FragmentManager:
mState=5 mIndex=2 mWho=android:fragment:0:2 mBackStackNesting=0 D/FragmentManager: mAdded=true mRemoving=false mFromLayout=false mInLayout=false D/FragmentManager:
mHidden=false mDetached=false mMenuVisible=true mHasMenu=false D/FragmentManager: mRetainInstance=false mRetaining=false mUserVisibleHint=true D/FragmentManager:
mFragmentManager=FragmentManager{aa7a54d in FragmentA{6948911}} D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:mParentFragment=FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager:
mArguments=Bundle[{TEXT=这是片段 B:2}] D/FragmentManager:
mContainer=android.widget.FrameLayout{918d881 V.E............ 0,0-800,1464 #3} D/FragmentManager:
mView=android.widget.LinearLayout{651ad26 V.E...... ........ 0,0-800,1464} D/FragmentManager:
mInnerView=android.widget.LinearLayout{651ad26 V.E...... ........ 0,0-800,1464} D/FragmentManager:孩子 FragmentManager{4ec7d67 in FragmentB{53c7c68}}:D/FragmentManager:
FragmentManager 杂项状态:D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:
mContainer=android.support.v4.app.Fragment$1@b90f714 D/FragmentManager:mParent=FragmentB{53c7c68 #2 id=0x3} D/FragmentManager: mCurState=5 mStateSaved=false mDestroyed=false D/FragmentManager: #3: FragmentB{30cad9b #3 id=0x4} D/FragmentManager:
mFragmentId=#4 mContainerId=#4 mTag=null D/FragmentManager:
mState=1 mIndex=3 mWho=android:fragment:0:3 mBackStackNesting=0 D/FragmentManager: mAdded=true mRemoving=false mFromLayout=false mInLayout=false D/FragmentManager:
mHidden=false mDetached=false mMenuVisible=true mHasMenu=false D/FragmentManager: mRetainInstance=false mRetaining=false mUserVisibleHint=true D/FragmentManager:
mFragmentManager=FragmentManager{aa7a54d in FragmentA{6948911}} D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:mParentFragment=FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager:
mArguments=Bundle[{TEXT=这是片段 B:3}] D/FragmentManager:
添加片段:D/FragmentManager:#0:FragmentB{44d0802 #0 id=0x1} D/FragmentManager: #1: FragmentB{d880f6f #1 id=0x2} D/FragmentManager: #2: FragmentB{53c7c68 #2 id=0x3} D/FragmentManager:#3:FragmentB{30cad9b #3 id=0x4} D/FragmentManager:FragmentManager 杂项状态: D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:
mContainer=android.support.v4.app.Fragment$1@5797bbd D/FragmentManager:mParent=FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager:mCurState=5 mStateSaved=false mDestroyed=false D/FragmentManager:已添加 片段:D/FragmentManager:#0:FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager:FragmentManager 杂项状态: D/FragmentManager:
mHost=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager:
mContainer=android.support.v4.app.FragmentActivity$HostCallbacks@327ba76 D/FragmentManager: mCurState=5 mStateSaved=false mDestroyed=false I/art: 做部分代码缓存收集,code=30KB, data=27KB I/art: 代码缓存收集后,code=29KB, data=27KB I/art: 增加 代码缓存容量为 128KB D/FragmentManager:查看层次结构: D/FragmentManager:com.android.internal.policy.DecorView{99b75b2 V.E..... ... 0,0-2560,1800} D/FragmentManager:
android.widget.LinearLayout{eb98903 V.E..... ... 0,0-2560,1704} D/FragmentManager: android.view.ViewStub{8107080 G.E....... 0,0-0,0 #10203ef android:id/action_mode_bar_stub} D/FragmentManager:
android.widget.FrameLayout{44716b9 V.E..... ... 0,48-2560,1704} D/FragmentManager:
android.support.v7.widget.ActionBarOverlayLayout{7473afe V.E....... 0,0-2560,1656 #7f0b0044 app:id/decor_content_parent} D/FragmentManager:
android.support.v7.widget.ContentFrameLayout{bc1b25f V.E....... 0,128-2560,1656 #1020002 android:id/content} D/FragmentManager:
android.widget.RelativeLayout{a4c14ac V.E..... ... 0,0-2560,1528

7f0b0055 app:id/activity_main} D/FragmentManager: android.widget.FrameLayout{ffe8877 V.E..... ... 128,32-2432,1496

7f0b0056 app:id/fragmentA} D/FragmentManager: android.widget.LinearLayout{ffe8ce4 V.E..... ... 0,0-2304,1464}

D/FragmentManager:
android.support.v7.widget.RecyclerView{9b96575 VFEDH...F.. 0,0-2304,1464 #7f0b0057 app:id/listView} D/FragmentManager:
android.widget.LinearLayout{e58090a V.E..... ... -19,0-781,1464} W/ResourceType:获取资源名称时没有包标识符 编号 0x00000001 D/FragmentManager:
android.widget.FrameLayout{c93513 V.E..... ... 0,0-800,1464 #1} D/FragmentManager:
android.widget.LinearLayout{3899350 V.E..... ... 0,0-800,1464} D/FragmentManager:
android.support.v7.widget.AppCompatTextView{5f9157b V.ED.... ... 0,0-254,38 #7f0b0070 app:id/textView} D/FragmentManager:
android.widget.LinearLayout{7bbcf98 V.E....... 781,0-1581,1464} W/ResourceType:获取资源名称时没有包标识符 编号 0x00000002 D/FragmentManager:
android.widget.FrameLayout{67c947c V.E..... ... 0,0-800,1464 #2} D/FragmentManager:
android.widget.LinearLayout{c313105 V.E..... ... 0,0-800,1464} D/FragmentManager:
android.support.v7.widget.AppCompatTextView{bc7e3f1 V.ED.... ... 0,0-254,38 #7f0b0070 app:id/textView} D/FragmentManager:
android.widget.LinearLayout{8f5abd6 V.E..... ... 1581,0-2381,1464} W/ResourceType:获取资源名称时没有包标识符 编号 0x00000003 D/FragmentManager:
android.widget.FrameLayout{918d881 V.E..... ... 0,0-800,1464 #3} D/FragmentManager:
android.widget.LinearLayout{651ad26 V.E..... ... 0,0-800,1464} D/FragmentManager:
android.support.v7.widget.AppCompatTextView{8798e57 V.ED.... ... 0,0-254,38 #7f0b0070 app:id/textView} D/FragmentManager:
android.support.v7.widget.ActionBarContainer{36a4d44 V.ED.... ... 0,0-2560,128 #7f0b0045 app:id/action_bar_container} D/FragmentManager: android.support.v7.widget.Toolbar{e65ce2d V.E..... 0,0-2560,128

7f0b0046 app:id/action_bar} D/FragmentManager: android.support.v7.widget.AppCompatTextView{9f8af62 V.ED.... ...

48,37-153,91} D/FragmentManager:
android.support.v7.widget.ActionMenuView{c1eb8f3 V.E....... 2544,0-2544,128} D/FragmentManager:
android.support.v7.widget.ActionBarContextView{460f9b0 G.E....... 0,0-0,0 #7f0b0047 app:id/action_context_bar} D/FragmentManager:
android.view.View{77e2029 V.ED.... 0,1704-2560,1800 #1020030 android:id/navigationBarBackground} D/FragmentManager:
android.view.View{7365fae V.ED.... 0,0-2560,48 #102002f android:id/statusBarBackground} D/AndroidRuntime: 关闭虚拟机 E/AndroidRuntime: 致命异常: main 进程:example.com.demo,PID:8156 java.lang.IllegalArgumentException:没有为片段 FragmentB{30cad9b #3 id=0x4} 找到 id 0x4(未知)的视图 在 android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1107) 在 android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1295) 在 android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801) 在 android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1682) 在 android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:541) 在 android.os.Handler.handleCallback(Handler.java:751) 在 android.os.Handler.dispatchMessage(Handler.java:95) 在 android.os.Looper.loop(Looper.java:154) 在 android.app.ActivityThread.main(ActivityThread.java:6119) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 与目标 VM 断开连接,地址:'localhost:8616',传输: '套接字'

两个主要类是 FragmentAAdapter 和 FragmentB(如果需要,可以在 git repo 中查看其他类):

public class FragmentAAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

FragmentA fragmentA;
Activity activity;
RecyclerView listView;

public FragmentAAdapter(FragmentA fragmentA, Activity activity, RecyclerView listView) {
    this.fragmentA = fragmentA;
    this.activity = activity;
    this.listView = listView;
}


@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_b, parent, false);
    RecyclerView.ViewHolder vh = new BoardViewHolder(v, this);
    return vh;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof BoardViewHolder){
        BoardViewHolder pHolder = (BoardViewHolder)holder;
        pHolder.onBindViewHolder(position);
    }
}

@Override
public int getItemCount() {
    return 10;
}

public class BoardViewHolder extends RecyclerView.ViewHolder {

    FragmentAAdapter adapter;
    FragmentB fragmentB;
    View view;

    public BoardViewHolder(View itemView, FragmentAAdapter adapter) {
        super(itemView);

        this.view = itemView;
        this.adapter = adapter;
    }

    public void onBindViewHolder(int position) {

        FragmentManager fm = fragmentA.getChildFragmentManager();
        if (fragmentB==null) {
            Bundle bundle = new Bundle();
            bundle.putString("TEXT", "This is Fragment B:" + position);
            fragmentB = FragmentB.getInstance(bundle);

            int boardId = generateViewId();
            // switch the id of the board to be unique
            View board = view.findViewById(R.id.board);
            board.setId(boardId);

            // now flip fragmentB
            FragmentTransaction ft = fm.beginTransaction();
            ft.replace(boardId, fragmentB);
            ft.commit();
        }
    }
}

private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);

public static int generateViewId() {
    for (;;) {
        final int result = sNextGeneratedId.get();
        // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
        int newValue = result + 1;
        if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
        if (sNextGeneratedId.compareAndSet(result, newValue)) {
            return result;
        }
    }
}

}

和片段B:

public class FragmentB extends Fragment {

View root;

Activity activity;

String text;
private TextView textView;

public static FragmentB getInstance(Bundle bundle) {
    FragmentB instance = new FragmentB();
    instance.setArguments(bundle);
    return instance;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    activity = (Activity) getActivity();

    if (getArguments()!=null) {
        text = getArguments().getString("TEXT");

    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);

    root = inflater.inflate(R.layout.row, null, false);

    textView = (TextView)root.findViewById(R.id.textView);
    textView.setText(text);

    return root;
}

}

完整代码:https://github.com/checklist/NestedFragmentsRecycler

谢谢!

【问题讨论】:

  • onCreateViewHolder 中生成新 ID,而不是 onBindViewHolder:您只需要与持有者/查看次数一样多的 ID
  • 已经尝试过了,得到了同样的异常
  • 在任何滚动之前,命令的输出是什么:adb shell dumpsys activity top?
  • 顺便说一句 - 我在平板电脑/手机客户端 (api v25) 上遇到了这个异常。在 api 19 上它不会经常崩溃。只是一个提示。这是转储:github.com/checklist/NestedFragmentsRecycler/blob/master/…
  • 好吧,不用生成 Id,将它们设置为视图,手动创建片段并使用 FragmentTransaction#replace 为什么不简单地在项目布局 xml 中使用 &lt;fragment ... 标签?

标签: android android-fragments android-recyclerview


【解决方案1】:

经过大量的灵魂搜索,我可以确认在片段内无法生成ID。如果你这样做了,Android 在渲染 UI 时会感到困惑,并且应用程序会崩溃。

我在另一个项目中尝试过这个,我们为单选按钮和组生成 ID,这些 ID 是动态生成并放置在片段和相同行为中的。两种解决方案: - 不要以编程方式创建,因此您不需要生成 id - 不要使用片段

【讨论】:

    猜你喜欢
    • 2015-09-18
    • 2015-05-18
    • 2017-01-14
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多