ViewPager2 迁移后出现无效 ID 0x00000001 错误

Posted

技术标签:

【中文标题】ViewPager2 迁移后出现无效 ID 0x00000001 错误【英文标题】:Invalid ID 0x00000001 errors after ViewPager2 migration 【发布时间】:2021-05-26 03:45:23 【问题描述】:

我使用 ViewPager 处理选项卡布局已经有一段时间了,但它已被弃用。 我按照官方文档迁移到ViewPager2, 一切正常,但我在每个片段上都收到以下错误:

无效的 ID 0x00000001 无效的 ID 0x00000001 无效的 ID 0x00000001

每次我在片段之间滑动时,这些都会增加.. 没有崩溃,但每次我重新打开活动时,数字都会增加到 Invalid ID 0x00000002 等等。

我对消除此错误的解决方案感到迷茫,但该应用仍可与新的 ViewPager2 一起使用。 任何想法来解决错误垃圾邮件?

活动代码:

//Responsible for adding the 4 tabs: NewLoot, ActiveLoot, SharedLoot, FinishedLoot
    private void setupViewPager()
        SectionsPagerAdapter adapter = new SectionsPagerAdapter(getSupportFragmentManager(),getLifecycle());
        adapter.addFragment(new NewLootFragment());//index 0
        adapter.addFragment(new ActiveLootFragment());//index 1
        adapter.addFragment(new FinishedLootFragment());//index 2
        ViewPager2 viewPager = (ViewPager2) findViewById(R.id.container);
        viewPager.setAdapter(adapter);
        final TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        new TabLayoutMediator(tabLayout, viewPager,
                new TabLayoutMediator.TabConfigurationStrategy() 
                    @Override
                    public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) 
                        //tab.setText("OBJECT " + (position + 1));
                    
                
        ).attach();
        tabLayout.getTabAt(0).setIcon(R.drawable.ic_search);
        tabLayout.getTabAt(1).setIcon(R.drawable.ic_arrow);
        tabLayout.getTabAt(2).setIcon(R.drawable.ic_action_name);

        tabLayout.getTabAt(0).getIcon().setColorFilter(getResources().getColor(R.color.red), PorterDuff.Mode.SRC_IN);
        tabLayout.getTabAt(1).getIcon().setColorFilter(getResources().getColor(android.R.color.black), PorterDuff.Mode.SRC_IN);
        tabLayout.getTabAt(2).getIcon().setColorFilter(getResources().getColor(android.R.color.black), PorterDuff.Mode.SRC_IN);

        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 
            @Override
            public void onTabSelected(TabLayout.Tab tab) 
                tab.view.getTab().getIcon().setColorFilter(getResources().getColor(R.color.red), PorterDuff.Mode.SRC_IN);
                       @Override
            public void onTabUnselected(TabLayout.Tab tab) 
                tab.view.getTab().getIcon().setColorFilter(getResources().getColor(android.R.color.black), PorterDuff.Mode.SRC_IN);
                       @Override
            public void onTabReselected(TabLayout.Tab tab) 
            
        );

    

SectionPagerAdapter 代码:

//Class that stores fragments for tabs
public class SectionsPagerAdapter extends FragmentStateAdapter 
    private static String TAG = "SectionsPagerAdapter";

    private final ArrayList<Fragment> mFragmentList = new ArrayList<>();

    public SectionsPagerAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle)
        super(fragmentManager, lifecycle);
    

    //public ViewPagerFragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) 
    //    super(fragmentManager, lifecycle);
    //

    public void addFragment(Fragment fragment)
        mFragmentList.add(fragment);
    

    @NonNull
    @Override
    public Fragment createFragment(int position) 
        return mFragmentList.get(position);
    

    @Override
    public int getItemCount() 
        return mFragmentList.size();
    

布局活动:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_
    android:layout_
    tools:context=".Loot.LootActivity">

    <RelativeLayout
        android:layout_
        android:layout_>

        <!-- Top Section (Toolbar) -->
        <RelativeLayout
            android:layout_
            android:layout_
            android:id="@+id/relLayout0">

            <include
                android:id="@+id/topViewBarHelper"
                layout="@layout/snippet_top_profilebar"
                android:layout_
                android:layout_/>

        </RelativeLayout>

        <!-- Top Section (Toolbar) -->
        <RelativeLayout
            android:layout_
            android:layout_
            android:id="@+id/relLayout1"
            android:layout_below="@+id/relLayout0">

            <include layout="@layout/layout_top_tabs"/>

        </RelativeLayout>

        <!-- Middle Section (Body) -->
        <RelativeLayout
            android:layout_
            android:layout_
            android:id="@+id/relLayout2"
            android:layout_below="@+id/relLayout1">

            <include layout="@layout/layout_center_viewpager"/>

        </RelativeLayout>

        <RelativeLayout
            android:layout_
            android:layout_
            android:id="@+id/relLayout3">

            <!-- Bottom Section (Navigation) -->
            <include layout="@layout/layout_bottom_navigation_view"/>

        </RelativeLayout>

    </RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

布局中心查看器:

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <RelativeLayout
        android:layout_
        android:layout_>
        
        <androidx.viewpager2.widget.ViewPager2
            android:id="@+id/container"
            android:layout_
            android:layout_
            android:layoutDirection="ltr">
        </androidx.viewpager2.widget.ViewPager2>

    </RelativeLayout>

</merge>

布局顶部标签:

<merge xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <RelativeLayout
        android:layout_
        android:layout_
        android:layout_alignParentTop="true">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_
            android:layout_
            android:id="@+id/AppBarLayout">

            <com.google.android.material.tabs.TabLayout
                android:layout_
                android:layout_
                android:id="@+id/tab_layout"
                android:background="@drawable/white_grey_border_bottom"
                app:tabIndicatorColor="@color/red"
                app:tabIndicatorHeight="4dp">
            </com.google.android.material.tabs.TabLayout>

        </com.google.android.material.appbar.AppBarLayout>

    </RelativeLayout>

</merge>

【问题讨论】:

同样的问题。 我遇到了同样的问题。有趣的是,它只出现在我的一台设备上,两台设备都运行 Android 11 (API 30)。在 Pixel 3a 上运行良好,在 OnePlus Nord 上获得 Invalid ID 0x00000001 【参考方案1】:

更新

因此,在我更新我的 Android Studio IDE 和无效缓存后,问题似乎消失了:

文件 -> 使缓存无效/重新启动...

另外值得注意的是,我现在使用的是Android Studio Arctic Fox | 2020.3.1 Canary 10 Build #AI-203.7148.57.2031.7194378,于 2021 年 3 月 9 日构建

升级后,我删除了所有以前的模拟器,以确保问题出在我的代码上。到目前为止,日志已经尽可能干净了。如果有变化会再次更新。

原帖

当我在 YouTube 上遇到 video by Android Developers 时,我正试图自己解决这个问题。

我观看了它并按照讲师概述的步骤进行操作。在那个视频中,大约在2:50,教练说:

“...您现在将使用 createFragment 代替 viewPager1 中的 getItem,是的,我们希望您为特定位置创建一个新片段。”

这句话让我相信他是在建议我们为特定位置创建一个新片段,而不是存储和重用片段。

因此,我停止将片段列表传递给我的 FragmentStateAdapter 实现,而是在 Kotlin 中使用 when 表达式,您可以使用 switch/case 作为替代在 java 中也是如此。

我的示例只有两个片段,但我希望你能明白:

    class MyAdapter(activity: AppCompatActivity) : FragmentStateAdapter(activity) 
        override fun getItemCount(): Int 
            return 2 // I just wanted 2 fragments in my app
        
    
        override fun createFragment(position: Int): Fragment 
            return when(position)
                0 -> Fragment1()
                1 -> Fragment2()
                else -> Fragment1() // this case should not happen but you can log it to debug console or do nothing !
            
        
    

我的 TabLayoutMediator 看起来像这样:

    TabLayoutMediator(tabLayout, viewPager, true ) tab, position ->
        tab.text = when(position)
            0 -> "Fragment1"
            1 -> "Fragment2"
            else -> "Unknown" // again, this case should not happen!
        
    .attach()

但是,尽管 INVALID ID 消失了一段时间,但没过多久它又回来并开始填充我的调试控制台。这很奇怪,因为近一个月以来我一直以同样的方式使用 view pager2,这是我第一次遇到错误,即今天。

我注意到我的模拟器在错误出现之前闪烁了一次,我附上了一些在屏幕闪烁和无效 ID 开始出现之前出现的日志,以防万一有人能找到发生了什么。

>mServiceHandler:Landroid/app/IntentService$ServiceHandler; (greylist, linking, allowed)
2021-03-15 21:08:42.046 9623-9623/com.kwaso.recorder W/.kwaso.recorde: Accessing hidden field Landroid/app/IntentService;->mRedelivery:Z (greylist-max-o, linking, denied)
2021-03-15 21:08:42.046 9623-9623/com.kwaso.recorder W/.kwaso.recorde: Accessing hidden field Landroid/app/IntentService;->mRedelivery:Z (greylist-max-o, linking, denied)
2021-03-15 21:08:42.057 9623-9623/com.kwaso.recorder W/.kwaso.recorde: Class android.os.PowerManager$WakeLock failed lock verification and will run slower.
2021-03-15 21:08:42.077 9623-9623/com.kwaso.recorder V/StudioProfiler: Profiler initialization complete on agent.
2021-03-15 21:08:42.079 9623-9737/com.kwaso.recorder V/StudioProfiler: Acquiring Application for Events
2021-03-15 21:08:42.083 9623-9738/com.kwaso.recorder W/InputMethodManager: InputMethodManager.getInstance() is deprecated because it cannot be compatible with multi-display. Use context.getSystemService(InputMethodManager.class) instead.
    java.lang.Throwable
        at android.view.inputmethod.InputMethodManager.getInstance(InputMethodManager.java:1234)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.tools.profiler.support.profilers.EventProfiler$InputConnectionHandler.run(EventProfiler.java:261)
        at java.lang.Thread.run(Thread.java:923)
2021-03-15 21:08:42.084 9623-9738/com.kwaso.recorder W/InputMethodManager: InputMethodManager.peekInstance() is deprecated because it cannot be compatible with multi-display. Use context.getSystemService(InputMethodManager.class) instead.
    java.lang.Throwable
        at android.view.inputmethod.InputMethodManager.peekInstance(InputMethodManager.java:1253)
        at android.view.inputmethod.InputMethodManager.getInstance(InputMethodManager.java:1239)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.tools.profiler.support.profilers.EventProfiler$InputConnectionHandler.run(EventProfiler.java:261)
        at java.lang.Thread.run(Thread.java:923)
2021-03-15 21:08:45.429 9623-9623/com.kwaso.recorder D/FilesFragment: onViewCreated: 
2021-03-15 21:08:45.464 9623-9740/com.kwaso.recorder D/UtilityFunctions: loadFilesInNewAPI: 
2021-03-15 21:08:50.128 9623-9712/com.kwaso.recorder V/StudioTransport: Transport agent connected to daemon.
2021-03-15 21:08:50.293 9623-9717/com.kwaso.recorder V/StudioTransport: Handling agent command 1100 for pid: 9623.
2021-03-15 21:08:50.293 9623-9717/com.kwaso.recorder V/StudioTransport: JNIEnv not attached
2021-03-15 21:08:50.368 9623-9623/com.kwaso.recorder E/.kwaso.recorde: Invalid ID 0x00000000.

这就是消息开始的时候。

此时我的猜测是,问题在于在创建/重新加载/恢复片段时未清除某些资源 ID。此外,应用程序不会崩溃或滞后,它只是在应用程序启动后 10 秒左右闪过一次屏幕,然后控制台中的混乱随之而来,UI 上什么也没有!

我把它放在这里,以便其他人可以阅读它并可能找到解决方案。

【讨论】:

以上是关于ViewPager2 迁移后出现无效 ID 0x00000001 错误的主要内容,如果未能解决你的问题,请参考以下文章

如何修复已启用探测器上的错误:无效地址 (0x0)?

iOS 错误 - CGContextRestoreGState:无效上下文 0x0

关闭 UIImageView 时上下文 0x0 无效

在迁移到 viewpager2 androidx 时发现此错误“无法解析方法 'super(androidx.fragment.app.FragmentManager)'”

为啥我在基于文档的应用程序中收到无效上下文 0x0 错误?

CGContextDrawImage:加载灰度图像时上下文 0x0 无效