1

My Android app crashes when resuming after being killed by OS due to low memory.

So I have built the smallest possible app to reproduce the bug. My app is composed of a MainActivity, which contains 1 page in a viewPager2, which contains a fragment. This fragment is added dynamically by replacing "structure_placeholder" (in the real app, the type of fragment depends on some parameters)

MainActivity.java:

public class MainActivity extends AppCompatActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this);
        ViewPager2 viewPage = findViewById(R.id.viewpager);
        viewPage.setAdapter(sectionsPagerAdapter);
    }

    /***************************************************************************/
    class SectionsPagerAdapter extends FragmentStateAdapter
    {
        private SectionsPagerAdapter(FragmentActivity fa)
        {
            super(fa);
        }

        @NonNull @Override
        public Fragment createFragment(int position)
        {
            return new MyPageFragment();
        }

        @Override
        public int getItemCount()
        {
            return 1;
        }
    }
}

activity_main.xml:

<LinearLayout
    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=".MainActivity">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

MyPageFragment.java:

public class MyPageFragment extends Fragment
{
    public MyPageFragment()
    { /* Required empty public constructor*/}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.my_page_fragment, container, false);
    }

    @Override
    public void onStart()
    {
        super.onStart();
        Fragment listFragment = SubFragment.newInstance();
        FragmentTransaction ft = requireActivity().getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.structure_placeholder, listFragment);
        ft.commit();
    }
}

my_page_fragment.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".MyPageFragment">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_blank_fragment" />

    <FrameLayout
        android:id="@+id/structure_placeholder"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        tools:layout_width="100dp"
        tools:layout_height="150dp"
        tools:background="@color/design_default_color_secondary"
        >
    </FrameLayout>
</LinearLayout>

SubFragment.java:

public class SubFragment extends Fragment
{
    public SubFragment()
    { /* Required empty public constructor*/ }

    public static SubFragment newInstance()
    {
        SubFragment fragment = new SubFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return inflater.inflate(R.layout.sub_fragment, container, false);
    }
}

sub_fragment.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/line1" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/line2" />
</LinearLayout>

Here is the error log when resuming the app after it has been killed:

2021-11-19 15:46:55.739 8298-8298/com.delrocq.mytestapp E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.delrocq.mytestapp, PID: 8298
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.delrocq.mytestapp/com.delrocq.mytestapp.MainActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f0801db (com.delrocq.mytestapp:id/structure_placeholder) for fragment SubFragment{9eb5496} (ada1c808-c885-49ed-9cd3-f4de1855c6af id=0x7f0801db)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6944)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
     Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f0801db (com.delrocq.mytestapp:id/structure_placeholder) for fragment SubFragment{9eb5496} (ada1c808-c885-49ed-9cd3-f4de1855c6af id=0x7f0801db)

I tried to put some logs to understand the lifecycle of the activity/fragments, but it did not help.

What am I doing wrong?

Laurent D.
  • 449
  • 4
  • 19
  • I would move subfragment creation to `onViewCreated` and use fragment-specific fragment manager instead of pulling one from activity. – Pawel Nov 19 '21 at 15:08
  • I moved subfragment creation to onViewCreated, and the app is still crashing. But I don't know how to use a fragment specific manager. – Laurent D. Nov 19 '21 at 15:23

1 Answers1

0

I finally found the solution after hours of searching and many wrong tracks. Inside a fragment, getChildFragmentManager() shall be used instead of getSupportFragmentManager(). It is so easy when you know it :)

Laurent D.
  • 449
  • 4
  • 19