Home > other >  Android view.setid(View.generateViewId()) does not work. It cannot find the view attached to
Android view.setid(View.generateViewId()) does not work. It cannot find the view attached to

Time:11-15

I try to insert a fragment (frag_bannerAds; frag_bannerAds contains another recyclerView actually) into one item of a recyclerView defined in a fragment file V_Room_Pub_LS_Frag.java (fragInst). The fragment frag_bannerAds is allocated in V_Room_Pub_LS_Frag.java (fragInst). I encounter a crash with below error when I smoothScroll the recyclerView. The weird thing is that it does not crash in real phone device. It crashed in Android emulator AVD (Pixel 3, API 27, x86). But it works fine in mulator AVD (Nexus 5, API 23, x86). It also crashed in Android emulator AVD (Pixel 3, API 29, x86_64).

Why is view id generated by newId = View.generateViewId() cannot find the view it attached to assgined by frag_bannerAds.setId(newId);?
What I am missing?
Why some device and emulator do not crash and work fine?

Output and error message:

----banner, after setId, frag_bannerAds=android.widget.FrameLayout{5f09291 V.E...... ......I. 0,0-0,0 #4}

----banner, after bannerAds_fragView_newUniqueId=4

----- fragInst.frag_bannerAds = V_Room_Pub_Banner_Frag{13cc5f6} (ec17bc37-7e02-4431-bb07-ca47dfbc3a5f)}

--------- beginning of crash E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.test1385, PID: 6612 java.lang.IllegalArgumentException: No view found for id 0x4 (unknown) for fragment V_Room_Pub_Banner_Frag{13cc5f6} (ec17bc37-7e02-4431-bb07-ca47dfbc3a5f) id=0x4 tag-abcd} at androidx.fragment.app.FragmentManager.K(SourceFile:27) at androidx.fragment.app.FragmentManager.I(SourceFile:1) at androidx.fragment.app.FragmentManager.J(Unknown Source:47)

In V_Room_Pub_LS_Frag.java :

     private V_Room_Pub_LS_Frag   mContext_fragInst  ;
     private List<V_Room_Pub_LS_Data> chatList;  
     public V_Room_Pub_Banner_Frag  frag_bannerAds ;         
     ....
     frag_bannerAds =   V_Room_Pub_Banner_Frag.newInstance();  
             //  allocte the fragment to be inserted here 
     ....
     mContext_fragInst = this ; 
     ...
     // define  recylerView 
    chatList = ...  ; 
    layoutManager = new LinearLayoutManager(mContext_this, LinearLayoutManager.VERTICAL,true);
    chatRecyclerView    = view.findViewById(R.id.chat_container);
    chatRecyclerView.setLayoutManager(layoutManager);
    chatAdapter         = new V_Room_Pub_LS_Adapter(mContext_fragInst, dbTableVar, chatList );
    chatRecyclerView.setAdapter(chatAdapter);
    chatRecyclerView.setMediaList(chatList, layoutManager);  
    ... 

In Adapter file V_Room_Pub_LS_Adapter.java :

    ...
    private V_Room_Pub_LS_Frag  fragInst;
    private List<V_Room_Pub_LS_Data> chatList; 
    ...

    public V_Room_Pub_LS_Adapter(V_Room_Pub_LS_Frag fragInst, String dbTableVar, List<V_Room_Pub_LS_Data> chatList) {
         this.fragInst = fragInst;
         this.dbTableVar  = dbTableVar;  this.chatList  = chatList;
    }

    @Override
    public V_Room_Pub_LS_Adapter.ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View  view ;
        V_Room_Pub_LS_Adapter.ItemViewHolder   itemViewHolder;
        switch (viewType) {
            case ViewType_Item:
            default:
                view =  LayoutInflater.from(parent.getContext()).inflate(R.layout.v_room_pub_ls_item, parent, false);
                itemViewHolder = new V_Room_Pub_LS_Adapter.ItemViewHolder(view , ViewType_Item);
                break;

            case ViewType_BannerAd:
                view =  LayoutInflater.from(parent.getContext()).inflate(R.layout.v_room_pub_ls_banner_ads, parent, false);
                itemViewHolder = new V_Room_Pub_LS_Adapter.ItemViewHolder(view , ViewType_BannerAd);
                break;
        }
        return itemViewHolder;
    }

    @Override
    public void onBindViewHolder(final V_Room_Pub_LS_Adapter.ItemViewHolder itemViewHolder, final int i) {
        final V_Room_Pub_LS_Data chatMsg = chatList.get(i);
        if( chatMsg.getViewType() == ViewType_BannerAd ){
            Log.d("fg_ccc","-----  fragInst.frag_bannerAds = "  fragInst.frag_bannerAds ) ;
            fragInst.getChildFragmentManager().beginTransaction().replace(
                    itemViewHolder.bannerAds_fragView_newUniqueId, 
                    fragInst.frag_bannerAds, "tag-abcd").commit();
            return ; 
        }
        ....
    }

   public class ItemViewHolder extends RecyclerView.ViewHolder {
     FrameLayout  frag_bannerAds ;
     int          bannerAds_fragView_newUniqueId;
     ...
     public ItemViewHolder(View itemView, Integer viewType) {
        super(itemView)
        if( viewType == ViewType_BannerAd ) {
            frag_bannerAds = itemView.findViewById(R.id.bannerads_list_frag); 
            // R.id.bannerads_list_frag is a frameLayout in  R.layout.v_room_pub_ls_banner_ads
            
            bannerAds_fragView_newUniqueId = View.generateViewId();   //  4 is generated 
            
            frag_bannerAds.setId(bannerAds_fragView_newUniqueId);
            
            Log.d("fg_ccc", "----banner, after setId, frag_bannerAds="   frag_bannerAds);
            Log.d("fg_ccc", "----banner, after bannerAds_fragView_newUniqueId="   bannerAds_fragView_newUniqueId);
            return ; 
        } 
        ... 
        ...
   }

CodePudding user response:

onBindViewHolder There seems to be a way to create a fragment and replace it by default. When I implemented the RecyclerView multi-layout before, because it was not created by default,Of course, this is just my personal suggestion.

CodePudding user response:

I advise against putting fragments in a RecyclerView. Particularly fragments which are switched out. The way a RecyclerView works is by creating a static set of views for a given item type. By doing fragment tranactions inside of it, you violate that assumption and will break the ability to recycle views properly. A static fragment might work, although I wouldn't suggest it and I'm not sure RecyclerView wouldn't screw up the lifecycle. But it should never be replaced out.

The correct way to do this is to use different item types for the different types of fragments you wish to display. Then instantiate the correct type of view in onCreateView for the different types.

  • Related