Invalid ID 0x00000001 errors after ViewPager2 migration

1

I have been working with a Tab layout with ViewPager for a while and it has gone deprecated. I followed the official documentation and migrated to ViewPager2, everything works but I am getting the following error on each fragment:

Invalid ID 0x00000001 Invalid ID 0x00000001 Invalid ID 0x00000001

And these will increase each time I slide between fragments.. No crash but every time I re-open the activity the number increases to Invalid ID 0x00000002 and so on.

I am lost with solutions to get this error away, but the app still works with the new ViewPager2. Any idea's to solve the error spam messages?

Activity code:

//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 code:

//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();
    }
}

Layout activity:

<?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_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Loot.LootActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- Top Section (Toolbar) -->
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/relLayout0">

            <include
                android:id="@+id/topViewBarHelper"
                layout="@layout/snippet_top_profilebar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </RelativeLayout>

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

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

        </RelativeLayout>

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

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

        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/relLayout3">

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

        </RelativeLayout>

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

layout center viewpager:

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

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

    </RelativeLayout>

</merge>

layout top tabs:

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

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_alignParentTop="true">

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

            <com.google.android.material.tabs.TabLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                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-viewpager
fragment
adapter
sections
migrating
asked on Stack Overflow Feb 23, 2021 by Robin K. • edited Feb 23, 2021 by Robin K.

1 Answer

0

UPDATE

So it seems that the problem is gone after I updated my Android Studio IDE and Invalidated caches by going to:

File -> Invalidate caches / restart...

It is also worth noting that I am now using Android Studio Arctic Fox | 2020.3.1 Canary 10 Build #AI-203.7148.57.2031.7194378, built on March 9, 2021

After upgrading, I deleted all previous emulators just to be sure that the issue was with my code. As of now, the logs are as clean as they can get. Will update again if something changes.

Original Post

I was trying to fix this issue myself when I came across a video by Android Developers on YouTube.

I watched it and followed the steps outlined by the instructor. In that video, at around 2:50, the instructor says:

"...and instead of using getItem from viewPager1, you'll now use createFragment, and yes, we want you to create a new fragment for the specific position."

This statement leads me to believe that he is suggesting that we create a new fragment for the specific position, instead of storing and reusing the fragments.

Accordingly, I stopped passing the fragment list to my implementation of the FragmentStateAdapter, instead used the when expression in Kotlin, you can use the switch/case as an alternative for the same in java.

My sample has just two fragments, but I hope you get the idea:

    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 {}!
            }
        }
    }

And my TabLayoutMediator looks something like this:

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

However, even though the INVALID ID disappeared for a bit, it wasn't long before it came back and started filling my debug console. It's weird coz I have been working with view pager2 in the same manner since almost a month and this is the first I am encountering the error, i.e., today.

I have noticed that my emulator flashes once before the error appears, I am attaching a few of the logs that appeared right before the screen flashed and the Invalid ID's started showing up, just in case anyone can find what's up.

>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.

and that's when the messages start.

At this point my guess is that the issue is with some Resource ID's not being cleared when the fragments are being created/reloaded/resumed. Also, the app doesn't crash, or lags, its just one flash of screen around 10 seconds after the app starts and the mess in the console follows, nothing on the UI!

I am putting this out here so that other's can read it and possibly find a solution.

answered on Stack Overflow Mar 15, 2021 by Tarique Ali Mirza • edited Mar 15, 2021 by Tarique Ali Mirza

User contributions licensed under CC BY-SA 3.0