Android Nested Fragments with a RecyclerView

0

I have a project (https://github.com/checklist/NestedFragmentsRecycler) with nested fragments. FragmentA is in the MainActivity and contains RecyclerView with an adapter. Each of the items in the adapter will have in return FragmentB. Since I need to give an id for loading FragmentB into position and it needs to be unique, I am generating my own ids. The first fragments are shown fine but unfortunately, the moment I start scrolling, I get an exception that my unique id cannot be found:

W/ResourceType: No package identifier when getting name for resource number 0x00000004 E/FragmentManager: No view found for id 0x4 (unknown) for fragment FragmentB{30cad9b #3 id=0x4} E/FragmentManager: Activity state: D/FragmentManager: Local FragmentActivity 6d29cb6 State: D/FragmentManager: mCreated=truemResumed=true mStopped=false mReallyStopped=false D/FragmentManager:
mLoadersStarted=true D/FragmentManager: Active Fragments in 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: Child FragmentManager{aa7a54d in FragmentA{6948911}}: D/FragmentManager: Active Fragments in 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=This is Fragment 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: Child FragmentManager{c564949 in FragmentB{44d0802}}: D/FragmentManager:
FragmentManager misc state: 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=This is Fragment 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: Child FragmentManager{cbf955a in FragmentB{d880f6f}}: D/FragmentManager:
FragmentManager misc state: 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=This is Fragment 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: Child FragmentManager{4ec7d67 in FragmentB{53c7c68}}: D/FragmentManager:
FragmentManager misc state: 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=This is Fragment B:3}] D/FragmentManager:
Added Fragments: 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 misc state: 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: Added Fragments: D/FragmentManager: #0: FragmentA{6948911 #0 id=0x7f0b0056} D/FragmentManager: FragmentManager misc state: 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: Do partial code cache collection, code=30KB, data=27KB I/art: After code cache collection, code=29KB, data=27KB I/art: Increasing code cache capacity to 128KB D/FragmentManager: View Hierarchy: 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: No package identifier when getting name for resource number 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: No package identifier when getting name for resource number 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: No package identifier when getting name for resource number 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: Shutting down VM E/AndroidRuntime: FATAL EXCEPTION: main Process: example.com.demo, PID: 8156 java.lang.IllegalArgumentException: No view found for id 0x4 (unknown) for fragment FragmentB{30cad9b #3 id=0x4} at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1107) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1295) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:801) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1682) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:541) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6119) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) Disconnected from the target VM, address: 'localhost:8616', transport: 'socket'

The 2 main classes are FragmentAAdapter and FragmentB (you can see the other classes if you need, in the 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;
        }
    }
}

}

and FragmentB:

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

}

Full code: https://github.com/checklist/NestedFragmentsRecycler

Thanks!

android
android-fragments
android-recyclerview
asked on Stack Overflow Nov 7, 2016 by checklist

1 Answer

1

After a lot of soul searching, I can confirm that it is not possible to generate IDs inside fragments. IF you do so, Android gets confused while rendering the UI and the app crashes.

I have tried this in another project where we generated ids for radio buttons and groups that were dynamically generated and placed within a fragment and same behavior. Two solutions: - do not create programatically so you don't need to generate ids - do not use fragments

answered on Stack Overflow Mar 6, 2017 by checklist

User contributions licensed under CC BY-SA 3.0