Android view.setid(View.generateViewId()) 不起作用。它找不到附加到的视图

Posted

技术标签:

【中文标题】Android view.setid(View.generateViewId()) 不起作用。它找不到附加到的视图【英文标题】:Android view.setid(View.generateViewId()) does not work. It cannot find the view attached to 【发布时间】:2021-12-25 19:36:24 【问题描述】:

我尝试将片段(frag_bannerAds;frag_bannerAds 实际上包含另一个 recyclerView)插入片段文件 V_Room_Pub_LS_Frag.java (fragInst) 中定义的 recyclerView 的一项中。片段 frag_bannerAds 分配在 V_Room_Pub_LS_Frag.java (fragInst) 中。当我对 recyclerView 进行平滑滚动时,我遇到了以下错误的崩溃。奇怪的是它不会在真实的手机设备中崩溃。它在 android 模拟器 AVD (Pixel 3, API 27, x86) 中崩溃。但它在 mulator AVD(Nexus 5、API 23、x86)中运行良好。它还在 Android 模拟器 AVD(Pixel 3,API 29,x86_64)中崩溃。

为什么 newId = View.generateViewId() 生成的视图 id 找不到 frag_bannerAds.setId(newId); 分配的视图? 我错过了什么? 为什么有些设备和模拟器不会崩溃并且工作正常?

输出和错误信息:

----banner,在setId之后,frag_bannerAds=android.widget.FrameLayout5f09291 V.E............I. 0,0-0,0 #4

----banner,bannerAds_fragView_newUniqueId=4 之后

----- fragInst.frag_bannerAds = V_Room_Pub_Banner_Frag13cc5f6 (ec17bc37-7e02-4431-bb07-ca47dfbc3a5f)

--------- 崩溃开始 E/AndroidRuntime: 致命异常: main 进程:com.example.test1385,PID:6612 java.lang.IllegalArgumentException:没有为片段 V_Room_Pub_Banner_Frag13cc5f6 (ec17bc37-7e02-4431-bb07-ca47dfbc3a5f) id=0x4 tag-abcd 找到 id 0x4(未知)的视图 在 androidx.fragment.app.FragmentManager.K(SourceFile:27) 在 androidx.fragment.app.FragmentManager.I(SourceFile:1) 在 androidx.fragment.app.FragmentManager.J(未知来源:47)

在 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);  
    ... 

在适配器文件 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 ; 
         
        ... 
        ...
   

【问题讨论】:

【参考方案1】:

onBindViewHolder 似乎有一种方法可以默认创建片段并替换它。之前实现RecyclerView多布局的时候,因为默认没有创建,当然这只是我个人的建议。

【讨论】:

正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。【参考方案2】:

我建议不要将片段放入 RecyclerView。特别是被关掉的片段。 RecyclerView 的工作方式是为给定的项目类型创建一组静态视图。通过在其中执行片段事务,您违反了该假设,并将破坏正确回收视图的能力。静态片段可能可以工作,虽然我不建议这样做,而且我不确定 RecyclerView 不会搞砸生命周期。但它永远不应该被替换掉。

执行此操作的正确方法是为您希望显示的不同类型的片段使用不同的项目类型。然后在 onCreateView 中为不同类型实例化正确类型的视图。

【讨论】:

我确实为不同的片段使用了项目类型。问题是某些模拟器无法识别 ItemViewHolder 类中的 framelayout.setId(newId)。它以后不识别视图。但是旧的模拟器可以工作。 @user2818066 最好不要在 RecyclerView 中使用片段。但是,如果您必须尝试(并且它们不会被放在一个中,所以如果您这样做,生命周期可能会被搞砸),那么就没有理由使用 setId。因为您永远不会使用 replace 将其切换出去,因为没有理由将其切换出去。您只会使用静态片段。

以上是关于Android view.setid(View.generateViewId()) 不起作用。它找不到附加到的视图的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式将 id 添加到 R.id

《Android Studio实用指南》4.27 使用演示模式

微信小程序

微信小程序——点击切换样式scroll-view

小程序日期时间段选择

以编程方式显示视图上下文显示