Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MainActivity.onCreate(null) called more than once in release builds #10266

Closed
igorclark opened this issue Oct 5, 2016 · 10 comments
Closed

MainActivity.onCreate(null) called more than once in release builds #10266

igorclark opened this issue Oct 5, 2016 · 10 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@igorclark
Copy link

Hello!

Issue Description

  • When running on-device in release mode, on the first run after a fresh install, MainActivity.onCreate() always seems to get null for its savedInstanceState parameter: firstly when the app starts, as expected, but then each time the app wakes after being backgrounded, every time the savedInstanceState parameter is null.
  • After killing and restarting the app, things behave as expected: the first call is passed null for savedInstanceState, again, and subsequent calls are either passed a proper Bundle of parcelled data, or aren't made at all.

The post-launch null Bundles are problematic for us as we expect to be able to do initialisation work in onCreate() - or at least to be able to use state data (saved in onSaveInstanceState() and passed in via onCreate's savedInstanceState parameter) to reconstruct our state in a new Activity if the OS kills the previous one. However what's actually happening is that on the first run of an app, when it's backgrounded and then foregrounded again, the Activity receives onCreate(null) a second time, so we have no chance to reconstruct any state as the passed-in Bundle is null, meaning the initialisation code overwrites any state, and our app-startup code gets properly tangled.

I looked at ReactActivity but all I can see is that its onCreate() method just calls super.onCreate() in android.app.Activity and then mDelegate.onCreate(), and I haven't been able to track this much further into RN so I don't know why this is happening, or the answer to any of these questions:

  • Is RN doing this? Is it Android? Is it just the Android 5.1 device we're using to test on?
  • If it's just the OS killing an activity and creating a new one as normal, why is the savedInstanceState's Bundle null in release mode?
  • Why does this happen in release mode but not in debug?

Any help or input would be very much appreciated, thanks!

Steps to Reproduce / Code Snippets

  1. Use this as MainActivity.java:
package com.yourapp;

import android.os.Bundle;
import android.util.Log;

import com.facebook.react.ReactActivity;

public class MainActivity extends ReactActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d( "ReactNativeDebugOutput", "MainActivity::onCreate() " + savedInstanceState );
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d( "ReactNativeDebugOutput", "MainActivity::onStart()" );
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d( "ReactNativeDebugOutput", "MainActivity::onRestart()" );
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d( "ReactNativeDebugOutput", "MainActivity::onResume()" );
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d( "ReactNativeDebugOutput", "MainActivity::onPause()" );
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d( "ReactNativeDebugOutput", "MainActivity::onStop()" );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d( "ReactNativeDebugOutput", "MainActivity::onDestroy()" );
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        Log.d( "ReactNativeDebugOutput", "MainActivity::onSaveInstanceState() " + savedInstanceState );
    }

    @Override
    public void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d( "ReactNativeDebugOutput", "MainActivity::onRestoreInstanceState() " + savedInstanceState );
    }

    /**
     * Returns the name of the main component registered from JavaScript.
     * This is used to schedule rendering of the component.
     */
    @Override
    protected String getMainComponentName() {
        return "YourAppName";
    }
}

2a. Run app in debug mode via Android Studio.
2b. Hit the home button to background the app
2c. Restart the app by tapping its icon
2d. Check the logs
2e. Kill the app using the process manager
2f. Start the app by tapping its icon
2g. Repeat steps 2b-2d

3a. Run app in release mode via react-native run-android --variant=release.
3b. Hit the home button to background the app
3c. Restart the app by tapping its icon
3d. Check the logs
3e. Kill the app using the process manager
3f. Start the app by tapping its icon
3g. Repeat steps 3b-3d

Expected Results

For each run, in debug and release mode respectively, I expect to see MainActivity::onCreate() null printed only once to the log, when the app is started and the activity in created, with any subsequent calls printing out a proper serialized Bundle value, passed in as savedInstanceState.

Actual Results

In debug mode, the results are as expected:

First run, immediately on being built & installed by Android Studio:

$ adb logcat | grep ReactNativeDebugOutput
D/ReactNativeDebugOutput(22588): MainActivity::onCreate() null
D/ReactNativeDebugOutput(22588): MainActivity::onStart()
D/ReactNativeDebugOutput(22588): MainActivity::onResume()
D/ReactNativeDebugOutput(22588): MainActivity::onPause()
D/ReactNativeDebugOutput(22588): MainActivity::onSaveInstanceState() Bundle[{android:viewHierarchyState=Bundle[{android:views={1=android.view.AbsSavedState$1@1244c50f, 4=android.view.AbsSavedState$1@1244c50f, 8=android.view.AbsSavedState$1@1244c50f, 9=android.view.AbsSavedState$1@1244c50f, 13=android.view.AbsSavedState$1@1244c50f, 14=android.view.AbsSavedState$1@1244c50f, 15=android.view.AbsSavedState$1@1244c50f, 16=android.view.AbsSavedState$1@1244c50f, 18=android.view.AbsSavedState$1@1244c50f, 22=android.view.AbsSavedState$1@1244c50f, 25=android.view.AbsSavedState$1@1244c50f, 29=HorizontalScrollView.SavedState{33eca99c scrollPosition=0 isLayoutRtl=false}, 30=android.view.AbsSavedState$1@1244c50f, 32=android.view.AbsSavedState$1@1244c50f, 33=android.view.AbsSavedState$1@1244c50f, 36=android.view.AbsSavedState$1@1244c50f, 38=android.view.AbsSavedState$1@1244c50f, 39=android.view.AbsSavedState$1@1244c50f, 43=android.view.AbsSavedState$1@1244c50f, 45=android.view.AbsSavedState$1@1244c50f, 47=android.view.AbsSavedState$1@1244c50f, 49=android.view.AbsSavedState$1@1244c50f, 50=android.view.AbsSavedState$1@1244c50f, 54=android.view.AbsSavedState$1@1244c50f, 57=android.view.AbsSavedState$1@1244c50f, 58=android.view.AbsSavedState$1@1244c50f, 62=android.view.AbsSavedState$1@1244c50f, 63=android.view.AbsSavedState$1@1244c50f, 64=android.view.AbsSavedState$1@1244c50f, 67=android.view.AbsSavedState$1@1244c50f, 70=android.view.AbsSavedState$1@1244c50f, 72=android.view.AbsSavedState$1@1244c50f, 74=android.view.AbsSavedState$1@1244c50f, 75=android.view.AbsSavedState$1@1244c50f, 78=android.view.AbsSavedState$1@1244c50f, 82=android.view.AbsSavedState$1@1244c50f, 83=android.view.AbsSavedState$1@1244c50f, 86=android.view.AbsSavedState$1@1244c50f, 87=android.view.AbsSavedState$1@1244c50f, 90=android.view.AbsSavedState$1@1244c50f, 92=android.view.AbsSavedState$1@1244c50f, 95=android.view.AbsSavedState$1@1244c50f, 96=android.view.AbsSavedState$1@1244c50f, 97=android.view.AbsSavedState$1@1244c50f, 100=android.view.AbsSavedState$1@1244c50f, 103=android.view.AbsSavedState$1@1244c50f, 104=android.view.AbsSavedState$1@1244c50f, 107=android.view.AbsSavedState$1@1244c50f, 109=android.view.AbsSavedState$1@1244c50f, 110=android.view.AbsSavedState$1@1244c50f, 112=android.view.AbsSavedState$1@1244c50f, 113=android.view.AbsSavedState$1@1244c50f, 114=android.view.AbsSavedState$1@1244c50f, 115=android.view.AbsSavedState$1@1244c50f, 116=android.view.AbsSavedState$1@1244c50f, 117=android.view.AbsSavedState$1@1244c50f, 118=android.view.AbsSavedState$1@1244c50f, 119=android.view.AbsSavedState$1@1244c50f, 120=android.view.AbsSavedState$1@1244c50f, 122=android.view.AbsSavedState$1@1244c50f, 123=android.view.AbsSavedState$1@1244c50f, 124=android.view.AbsSavedState$1@1244c50f, 125=android.view.AbsSavedState$1@1244c50f, 126=android.view.AbsSavedState$1@1244c50f, 128=android.view.AbsSavedState$1@1244c50f, 130=android.view.AbsSavedState$1@1244c50f, 16908290=android.view.AbsSavedState$1@1244c50f}}]}]
D/ReactNativeDebugOutput(22588): MainActivity::onStop()
D/ReactNativeDebugOutput(22588): MainActivity::onDestroy()
D/ReactNativeDebugOutput(22588): MainActivity::onCreate() Bundle[{android:viewHierarchyState=Bundle[mParcelledData.dataSize=5180]}]
D/ReactNativeDebugOutput(22588): MainActivity::onStart()
D/ReactNativeDebugOutput(22588): MainActivity::onRestoreInstanceState() Bundle[{android:viewHierarchyState=Bundle[{android:views={1=android.view.AbsSavedState$1@1244c50f, 4=android.view.AbsSavedState$1@1244c50f, 8=android.view.AbsSavedState$1@1244c50f, 9=android.view.AbsSavedState$1@1244c50f, 13=android.view.AbsSavedState$1@1244c50f, 14=android.view.AbsSavedState$1@1244c50f, 15=android.view.AbsSavedState$1@1244c50f, 16=android.view.AbsSavedState$1@1244c50f, 18=android.view.AbsSavedState$1@1244c50f, 22=android.view.AbsSavedState$1@1244c50f, 25=android.view.AbsSavedState$1@1244c50f, 29=HorizontalScrollView.SavedState{360a9034 scrollPosition=0 isLayoutRtl=true}, 30=android.view.AbsSavedState$1@1244c50f, 32=android.view.AbsSavedState$1@1244c50f, 33=android.view.AbsSavedState$1@1244c50f, 36=android.view.AbsSavedState$1@1244c50f, 38=android.view.AbsSavedState$1@1244c50f, 39=android.view.AbsSavedState$1@1244c50f, 43=android.view.AbsSavedState$1@1244c50f, 45=android.view.AbsSavedState$1@1244c50f, 47=android.view.AbsSavedState$1@1244c50f, 49=android.view.AbsSavedState$1@1244c50f, 50=android.view.AbsSavedState$1@1244c50f, 54=android.view.AbsSavedState$1@1244c50f, 57=android.view.AbsSavedState$1@1244c50f, 58=android.view.AbsSavedState$1@1244c50f, 62=android.view.AbsSavedState$1@1244c50f, 63=android.view.AbsSavedState$1@1244c50f, 64=android.view.AbsSavedState$1@1244c50f, 67=android.view.AbsSavedState$1@1244c50f, 70=android.view.AbsSavedState$1@1244c50f, 72=android.view.AbsSavedState$1@1244c50f, 74=android.view.AbsSavedState$1@1244c50f, 75=android.view.AbsSavedState$1@1244c50f, 78=android.view.AbsSavedState$1@1244c50f, 82=android.view.AbsSavedState$1@1244c50f, 83=android.view.AbsSavedState$1@1244c50f, 86=android.view.AbsSavedState$1@1244c50f, 87=android.view.AbsSavedState$1@1244c50f, 90=android.view.AbsSavedState$1@1244c50f, 92=android.view.AbsSavedState$1@1244c50f, 95=android.view.AbsSavedState$1@1244c50f, 96=android.view.AbsSavedState$1@1244c50f, 97=android.view.AbsSavedState$1@1244c50f, 100=android.view.AbsSavedState$1@1244c50f, 103=android.view.AbsSavedState$1@1244c50f, 104=android.view.AbsSavedState$1@1244c50f, 107=android.view.AbsSavedState$1@1244c50f, 109=android.view.AbsSavedState$1@1244c50f, 110=android.view.AbsSavedState$1@1244c50f, 112=android.view.AbsSavedState$1@1244c50f, 113=android.view.AbsSavedState$1@1244c50f, 114=android.view.AbsSavedState$1@1244c50f, 115=android.view.AbsSavedState$1@1244c50f, 116=android.view.AbsSavedState$1@1244c50f, 117=android.view.AbsSavedState$1@1244c50f, 118=android.view.AbsSavedState$1@1244c50f, 119=android.view.AbsSavedState$1@1244c50f, 120=android.view.AbsSavedState$1@1244c50f, 122=android.view.AbsSavedState$1@1244c50f, 123=android.view.AbsSavedState$1@1244c50f, 124=android.view.AbsSavedState$1@1244c50f, 125=android.view.AbsSavedState$1@1244c50f, 126=android.view.AbsSavedState$1@1244c50f, 128=android.view.AbsSavedState$1@1244c50f, 130=android.view.AbsSavedState$1@1244c50f, 16908290=android.view.AbsSavedState$1@1244c50f}}]}]
D/ReactNativeDebugOutput(22588): MainActivity::onResume() 

Second run, after killing the app process with a swipe and restarting the app:

$ adb logcat | grep ReactNativeDebugOutput
D/ReactNativeDebugOutput(24235): MainActivity::onCreate() null
D/ReactNativeDebugOutput(24235): MainActivity::onStart()
D/ReactNativeDebugOutput(24235): MainActivity::onResume()
D/ReactNativeDebugOutput(24235): MainActivity::onPause()
D/ReactNativeDebugOutput(24235): MainActivity::onSaveInstanceState() Bundle[{android:viewHierarchyState=Bundle[{android:views={1=android.view.AbsSavedState$1@205baac5, 4=android.view.AbsSavedState$1@205baac5, 8=android.view.AbsSavedState$1@205baac5, 9=android.view.AbsSavedState$1@205baac5, 13=android.view.AbsSavedState$1@205baac5, 14=android.view.AbsSavedState$1@205baac5, 15=android.view.AbsSavedState$1@205baac5, 16=android.view.AbsSavedState$1@205baac5, 18=android.view.AbsSavedState$1@205baac5, 22=android.view.AbsSavedState$1@205baac5, 25=android.view.AbsSavedState$1@205baac5, 29=HorizontalScrollView.SavedState{e6dec1a scrollPosition=0 isLayoutRtl=false}, 30=android.view.AbsSavedState$1@205baac5, 32=android.view.AbsSavedState$1@205baac5, 33=android.view.AbsSavedState$1@205baac5, 36=android.view.AbsSavedState$1@205baac5, 38=android.view.AbsSavedState$1@205baac5, 39=android.view.AbsSavedState$1@205baac5, 43=android.view.AbsSavedState$1@205baac5, 45=android.view.AbsSavedState$1@205baac5, 47=android.view.AbsSavedState$1@205baac5, 49=android.view.AbsSavedState$1@205baac5, 50=android.view.AbsSavedState$1@205baac5, 54=android.view.AbsSavedState$1@205baac5, 57=android.view.AbsSavedState$1@205baac5, 58=android.view.AbsSavedState$1@205baac5, 62=android.view.AbsSavedState$1@205baac5, 63=android.view.AbsSavedState$1@205baac5, 64=android.view.AbsSavedState$1@205baac5, 67=android.view.AbsSavedState$1@205baac5, 70=android.view.AbsSavedState$1@205baac5, 72=android.view.AbsSavedState$1@205baac5, 74=android.view.AbsSavedState$1@205baac5, 75=android.view.AbsSavedState$1@205baac5, 78=android.view.AbsSavedState$1@205baac5, 82=android.view.AbsSavedState$1@205baac5, 83=android.view.AbsSavedState$1@205baac5, 86=android.view.AbsSavedState$1@205baac5, 87=android.view.AbsSavedState$1@205baac5, 90=android.view.AbsSavedState$1@205baac5, 92=android.view.AbsSavedState$1@205baac5, 95=android.view.AbsSavedState$1@205baac5, 96=android.view.AbsSavedState$1@205baac5, 97=android.view.AbsSavedState$1@205baac5, 100=android.view.AbsSavedState$1@205baac5, 103=android.view.AbsSavedState$1@205baac5, 104=android.view.AbsSavedState$1@205baac5, 107=android.view.AbsSavedState$1@205baac5, 109=android.view.AbsSavedState$1@205baac5, 110=android.view.AbsSavedState$1@205baac5, 112=android.view.AbsSavedState$1@205baac5, 113=android.view.AbsSavedState$1@205baac5, 114=android.view.AbsSavedState$1@205baac5, 115=android.view.AbsSavedState$1@205baac5, 116=android.view.AbsSavedState$1@205baac5, 117=android.view.AbsSavedState$1@205baac5, 118=android.view.AbsSavedState$1@205baac5, 119=android.view.AbsSavedState$1@205baac5, 120=android.view.AbsSavedState$1@205baac5, 122=android.view.AbsSavedState$1@205baac5, 123=android.view.AbsSavedState$1@205baac5, 124=android.view.AbsSavedState$1@205baac5, 125=android.view.AbsSavedState$1@205baac5, 126=android.view.AbsSavedState$1@205baac5, 128=android.view.AbsSavedState$1@205baac5, 130=android.view.AbsSavedState$1@205baac5, 16908290=android.view.AbsSavedState$1@205baac5}}]}]
D/ReactNativeDebugOutput(24235): MainActivity::onStop()
D/ReactNativeDebugOutput(24235): MainActivity::onDestroy()
D/ReactNativeDebugOutput(24235): MainActivity::onCreate() Bundle[{android:viewHierarchyState=Bundle[mParcelledData.dataSize=5180]}]
D/ReactNativeDebugOutput(24235): MainActivity::onStart()
D/ReactNativeDebugOutput(24235): MainActivity::onRestoreInstanceState() Bundle[{android:viewHierarchyState=Bundle[{android:views={1=android.view.AbsSavedState$1@205baac5, 4=android.view.AbsSavedState$1@205baac5, 8=android.view.AbsSavedState$1@205baac5, 9=android.view.AbsSavedState$1@205baac5, 13=android.view.AbsSavedState$1@205baac5, 14=android.view.AbsSavedState$1@205baac5, 15=android.view.AbsSavedState$1@205baac5, 16=android.view.AbsSavedState$1@205baac5, 18=android.view.AbsSavedState$1@205baac5, 22=android.view.AbsSavedState$1@205baac5, 25=android.view.AbsSavedState$1@205baac5, 29=HorizontalScrollView.SavedState{265e472 scrollPosition=0 isLayoutRtl=true}, 30=android.view.AbsSavedState$1@205baac5, 32=android.view.AbsSavedState$1@205baac5, 33=android.view.AbsSavedState$1@205baac5, 36=android.view.AbsSavedState$1@205baac5, 38=android.view.AbsSavedState$1@205baac5, 39=android.view.AbsSavedState$1@205baac5, 43=android.view.AbsSavedState$1@205baac5, 45=android.view.AbsSavedState$1@205baac5, 47=android.view.AbsSavedState$1@205baac5, 49=android.view.AbsSavedState$1@205baac5, 50=android.view.AbsSavedState$1@205baac5, 54=android.view.AbsSavedState$1@205baac5, 57=android.view.AbsSavedState$1@205baac5, 58=android.view.AbsSavedState$1@205baac5, 62=android.view.AbsSavedState$1@205baac5, 63=android.view.AbsSavedState$1@205baac5, 64=android.view.AbsSavedState$1@205baac5, 67=android.view.AbsSavedState$1@205baac5, 70=android.view.AbsSavedState$1@205baac5, 72=android.view.AbsSavedState$1@205baac5, 74=android.view.AbsSavedState$1@205baac5, 75=android.view.AbsSavedState$1@205baac5, 78=android.view.AbsSavedState$1@205baac5, 82=android.view.AbsSavedState$1@205baac5, 83=android.view.AbsSavedState$1@205baac5, 86=android.view.AbsSavedState$1@205baac5, 87=android.view.AbsSavedState$1@205baac5, 90=android.view.AbsSavedState$1@205baac5, 92=android.view.AbsSavedState$1@205baac5, 95=android.view.AbsSavedState$1@205baac5, 96=android.view.AbsSavedState$1@205baac5, 97=android.view.AbsSavedState$1@205baac5, 100=android.view.AbsSavedState$1@205baac5, 103=android.view.AbsSavedState$1@205baac5, 104=android.view.AbsSavedState$1@205baac5, 107=android.view.AbsSavedState$1@205baac5, 109=android.view.AbsSavedState$1@205baac5, 110=android.view.AbsSavedState$1@205baac5, 112=android.view.AbsSavedState$1@205baac5, 113=android.view.AbsSavedState$1@205baac5, 114=android.view.AbsSavedState$1@205baac5, 115=android.view.AbsSavedState$1@205baac5, 116=android.view.AbsSavedState$1@205baac5, 117=android.view.AbsSavedState$1@205baac5, 118=android.view.AbsSavedState$1@205baac5, 119=android.view.AbsSavedState$1@205baac5, 120=android.view.AbsSavedState$1@205baac5, 122=android.view.AbsSavedState$1@205baac5, 123=android.view.AbsSavedState$1@205baac5, 124=android.view.AbsSavedState$1@205baac5, 125=android.view.AbsSavedState$1@205baac5, 126=android.view.AbsSavedState$1@205baac5, 128=android.view.AbsSavedState$1@205baac5, 130=android.view.AbsSavedState$1@205baac5, 16908290=android.view.AbsSavedState$1@205baac5}}]}]
D/ReactNativeDebugOutput(24235): MainActivity::onResume()

(So far, so good.)

In release mode, the results are as described in the Issue Description:

First run:

$ adb logcat | grep ReactNativeDebugOutput
D/ReactNativeDebugOutput(26538): MainActivity::onCreate() null
D/ReactNativeDebugOutput(26538): MainActivity::onStart()
D/ReactNativeDebugOutput(26538): MainActivity::onResume()
D/ReactNativeDebugOutput(26538): MainActivity::onPause()
D/ReactNativeDebugOutput(26538): MainActivity::onSaveInstanceState() Bundle[{android:viewHierarchyState=Bundle[{android:views={1=android.view.AbsSavedState$1@2d5b6cd3, 4=android.view.AbsSavedState$1@2d5b6cd3, 7=android.view.AbsSavedState$1@2d5b6cd3, 8=android.view.AbsSavedState$1@2d5b6cd3, 12=android.view.AbsSavedState$1@2d5b6cd3, 13=android.view.AbsSavedState$1@2d5b6cd3, 14=android.view.AbsSavedState$1@2d5b6cd3, 15=android.view.AbsSavedState$1@2d5b6cd3, 17=android.view.AbsSavedState$1@2d5b6cd3, 20=android.view.AbsSavedState$1@2d5b6cd3, 24=android.view.AbsSavedState$1@2d5b6cd3, 28=HorizontalScrollView.SavedState{2947d010 scrollPosition=0 isLayoutRtl=false}, 29=android.view.AbsSavedState$1@2d5b6cd3, 30=android.view.AbsSavedState$1@2d5b6cd3, 32=android.view.AbsSavedState$1@2d5b6cd3, 35=android.view.AbsSavedState$1@2d5b6cd3, 37=android.view.AbsSavedState$1@2d5b6cd3, 38=android.view.AbsSavedState$1@2d5b6cd3, 42=android.view.AbsSavedState$1@2d5b6cd3, 44=android.view.AbsSavedState$1@2d5b6cd3, 46=android.view.AbsSavedState$1@2d5b6cd3, 48=android.view.AbsSavedState$1@2d5b6cd3, 49=android.view.AbsSavedState$1@2d5b6cd3, 53=android.view.AbsSavedState$1@2d5b6cd3, 56=android.view.AbsSavedState$1@2d5b6cd3, 57=android.view.AbsSavedState$1@2d5b6cd3, 60=android.view.AbsSavedState$1@2d5b6cd3, 62=android.view.AbsSavedState$1@2d5b6cd3, 63=android.view.AbsSavedState$1@2d5b6cd3, 66=android.view.AbsSavedState$1@2d5b6cd3, 69=android.view.AbsSavedState$1@2d5b6cd3, 70=android.view.AbsSavedState$1@2d5b6cd3, 73=android.view.AbsSavedState$1@2d5b6cd3, 74=android.view.AbsSavedState$1@2d5b6cd3, 77=android.view.AbsSavedState$1@2d5b6cd3, 80=android.view.AbsSavedState$1@2d5b6cd3, 82=android.view.AbsSavedState$1@2d5b6cd3, 85=android.view.AbsSavedState$1@2d5b6cd3, 86=android.view.AbsSavedState$1@2d5b6cd3, 89=android.view.AbsSavedState$1@2d5b6cd3, 90=android.view.AbsSavedState$1@2d5b6cd3, 94=android.view.AbsSavedState$1@2d5b6cd3, 95=android.view.AbsSavedState$1@2d5b6cd3, 96=android.view.AbsSavedState$1@2d5b6cd3, 99=android.view.AbsSavedState$1@2d5b6cd3, 102=android.view.AbsSavedState$1@2d5b6cd3, 103=android.view.AbsSavedState$1@2d5b6cd3, 106=android.view.AbsSavedState$1@2d5b6cd3, 108=android.view.AbsSavedState$1@2d5b6cd3, 109=android.view.AbsSavedState$1@2d5b6cd3, 110=android.view.AbsSavedState$1@2d5b6cd3, 112=android.view.AbsSavedState$1@2d5b6cd3, 113=android.view.AbsSavedState$1@2d5b6cd3, 114=android.view.AbsSavedState$1@2d5b6cd3, 115=android.view.AbsSavedState$1@2d5b6cd3, 116=android.view.AbsSavedState$1@2d5b6cd3, 117=android.view.AbsSavedState$1@2d5b6cd3, 118=android.view.AbsSavedState$1@2d5b6cd3, 119=android.view.AbsSavedState$1@2d5b6cd3, 120=android.view.AbsSavedState$1@2d5b6cd3, 122=android.view.AbsSavedState$1@2d5b6cd3, 123=android.view.AbsSavedState$1@2d5b6cd3, 124=android.view.AbsSavedState$1@2d5b6cd3, 125=android.view.AbsSavedState$1@2d5b6cd3, 127=android.view.AbsSavedState$1@2d5b6cd3, 129=android.view.AbsSavedState$1@2d5b6cd3, 16908290=android.view.AbsSavedState$1@2d5b6cd3}}]}]
D/ReactNativeDebugOutput(26538): MainActivity::onStop()
D/ReactNativeDebugOutput(26538): MainActivity::onDestroy()
D/ReactNativeDebugOutput(26538): MainActivity::onCreate() null # <-- HERE'S THE PROBLEM
D/ReactNativeDebugOutput(26538): MainActivity::onStart()
D/ReactNativeDebugOutput(26538): MainActivity::onResume()

Second run, after killing the app process with a swipe in the process manager and restarting the app:

D/ReactNativeDebugOutput(26939): MainActivity::onCreate() null
D/ReactNativeDebugOutput(26939): MainActivity::onStart()
D/ReactNativeDebugOutput(26939): MainActivity::onResume()
D/ReactNativeDebugOutput(26939): MainActivity::onPause()
D/ReactNativeDebugOutput(26939): MainActivity::onSaveInstanceState() Bundle[{android:viewHierarchyState=Bundle[{android:views={1=android.view.AbsSavedState$1@1cea46c2, 4=android.view.AbsSavedState$1@1cea46c2, 7=android.view.AbsSavedState$1@1cea46c2, 8=android.view.AbsSavedState$1@1cea46c2, 12=android.view.AbsSavedState$1@1cea46c2, 13=android.view.AbsSavedState$1@1cea46c2, 14=android.view.AbsSavedState$1@1cea46c2, 15=android.view.AbsSavedState$1@1cea46c2, 17=android.view.AbsSavedState$1@1cea46c2, 20=android.view.AbsSavedState$1@1cea46c2, 24=android.view.AbsSavedState$1@1cea46c2, 28=HorizontalScrollView.SavedState{2d5b6cd3 scrollPosition=0 isLayoutRtl=false}, 29=android.view.AbsSavedState$1@1cea46c2, 30=android.view.AbsSavedState$1@1cea46c2, 32=android.view.AbsSavedState$1@1cea46c2, 35=android.view.AbsSavedState$1@1cea46c2, 37=android.view.AbsSavedState$1@1cea46c2, 38=android.view.AbsSavedState$1@1cea46c2, 42=android.view.AbsSavedState$1@1cea46c2, 44=android.view.AbsSavedState$1@1cea46c2, 46=android.view.AbsSavedState$1@1cea46c2, 48=android.view.AbsSavedState$1@1cea46c2, 49=android.view.AbsSavedState$1@1cea46c2, 53=android.view.AbsSavedState$1@1cea46c2, 56=android.view.AbsSavedState$1@1cea46c2, 57=android.view.AbsSavedState$1@1cea46c2, 60=android.view.AbsSavedState$1@1cea46c2, 62=android.view.AbsSavedState$1@1cea46c2, 63=android.view.AbsSavedState$1@1cea46c2, 66=android.view.AbsSavedState$1@1cea46c2, 69=android.view.AbsSavedState$1@1cea46c2, 70=android.view.AbsSavedState$1@1cea46c2, 73=android.view.AbsSavedState$1@1cea46c2, 74=android.view.AbsSavedState$1@1cea46c2, 77=android.view.AbsSavedState$1@1cea46c2, 80=android.view.AbsSavedState$1@1cea46c2, 82=android.view.AbsSavedState$1@1cea46c2, 85=android.view.AbsSavedState$1@1cea46c2, 86=android.view.AbsSavedState$1@1cea46c2, 89=android.view.AbsSavedState$1@1cea46c2, 90=android.view.AbsSavedState$1@1cea46c2, 94=android.view.AbsSavedState$1@1cea46c2, 95=android.view.AbsSavedState$1@1cea46c2, 96=android.view.AbsSavedState$1@1cea46c2, 99=android.view.AbsSavedState$1@1cea46c2, 102=android.view.AbsSavedState$1@1cea46c2, 103=android.view.AbsSavedState$1@1cea46c2, 106=android.view.AbsSavedState$1@1cea46c2, 108=android.view.AbsSavedState$1@1cea46c2, 109=android.view.AbsSavedState$1@1cea46c2, 110=android.view.AbsSavedState$1@1cea46c2, 112=android.view.AbsSavedState$1@1cea46c2, 113=android.view.AbsSavedState$1@1cea46c2, 114=android.view.AbsSavedState$1@1cea46c2, 115=android.view.AbsSavedState$1@1cea46c2, 116=android.view.AbsSavedState$1@1cea46c2, 117=android.view.AbsSavedState$1@1cea46c2, 118=android.view.AbsSavedState$1@1cea46c2, 119=android.view.AbsSavedState$1@1cea46c2, 120=android.view.AbsSavedState$1@1cea46c2, 122=android.view.AbsSavedState$1@1cea46c2, 123=android.view.AbsSavedState$1@1cea46c2, 124=android.view.AbsSavedState$1@1cea46c2, 125=android.view.AbsSavedState$1@1cea46c2, 127=android.view.AbsSavedState$1@1cea46c2, 129=android.view.AbsSavedState$1@1cea46c2, 16908290=android.view.AbsSavedState$1@1cea46c2}}]}]
D/ReactNativeDebugOutput(26939): MainActivity::onStop()
D/ReactNativeDebugOutput(26939): MainActivity::onDestroy()
D/ReactNativeDebugOutput(26939): MainActivity::onCreate() Bundle[{android:viewHierarchyState=Bundle[mParcelledData.dataSize=5180]}]
D/ReactNativeDebugOutput(26939): MainActivity::onStart()
D/ReactNativeDebugOutput(26939): MainActivity::onRestoreInstanceState() Bundle[{android:viewHierarchyState=Bundle[{android:views={1=android.view.AbsSavedState$1@1cea46c2, 4=android.view.AbsSavedState$1@1cea46c2, 7=android.view.AbsSavedState$1@1cea46c2, 8=android.view.AbsSavedState$1@1cea46c2, 12=android.view.AbsSavedState$1@1cea46c2, 13=android.view.AbsSavedState$1@1cea46c2, 14=android.view.AbsSavedState$1@1cea46c2, 15=android.view.AbsSavedState$1@1cea46c2, 17=android.view.AbsSavedState$1@1cea46c2, 20=android.view.AbsSavedState$1@1cea46c2, 24=android.view.AbsSavedState$1@1cea46c2, 28=HorizontalScrollView.SavedState{18d9a34b scrollPosition=0 isLayoutRtl=true}, 29=android.view.AbsSavedState$1@1cea46c2, 30=android.view.AbsSavedState$1@1cea46c2, 32=android.view.AbsSavedState$1@1cea46c2, 35=android.view.AbsSavedState$1@1cea46c2, 37=android.view.AbsSavedState$1@1cea46c2, 38=android.view.AbsSavedState$1@1cea46c2, 42=android.view.AbsSavedState$1@1cea46c2, 44=android.view.AbsSavedState$1@1cea46c2, 46=android.view.AbsSavedState$1@1cea46c2, 48=android.view.AbsSavedState$1@1cea46c2, 49=android.view.AbsSavedState$1@1cea46c2, 53=android.view.AbsSavedState$1@1cea46c2, 56=android.view.AbsSavedState$1@1cea46c2, 57=android.view.AbsSavedState$1@1cea46c2, 60=android.view.AbsSavedState$1@1cea46c2, 62=android.view.AbsSavedState$1@1cea46c2, 63=android.view.AbsSavedState$1@1cea46c2, 66=android.view.AbsSavedState$1@1cea46c2, 69=android.view.AbsSavedState$1@1cea46c2, 70=android.view.AbsSavedState$1@1cea46c2, 73=android.view.AbsSavedState$1@1cea46c2, 74=android.view.AbsSavedState$1@1cea46c2, 77=android.view.AbsSavedState$1@1cea46c2, 80=android.view.AbsSavedState$1@1cea46c2, 82=android.view.AbsSavedState$1@1cea46c2, 85=android.view.AbsSavedState$1@1cea46c2, 86=android.view.AbsSavedState$1@1cea46c2, 89=android.view.AbsSavedState$1@1cea46c2, 90=android.view.AbsSavedState$1@1cea46c2, 94=android.view.AbsSavedState$1@1cea46c2, 95=android.view.AbsSavedState$1@1cea46c2, 96=android.view.AbsSavedState$1@1cea46c2, 99=android.view.AbsSavedState$1@1cea46c2, 102=android.view.AbsSavedState$1@1cea46c2, 103=android.view.AbsSavedState$1@1cea46c2, 106=android.view.AbsSavedState$1@1cea46c2, 108=android.view.AbsSavedState$1@1cea46c2, 109=android.view.AbsSavedState$1@1cea46c2, 110=android.view.AbsSavedState$1@1cea46c2, 112=android.view.AbsSavedState$1@1cea46c2, 113=android.view.AbsSavedState$1@1cea46c2, 114=android.view.AbsSavedState$1@1cea46c2, 115=android.view.AbsSavedState$1@1cea46c2, 116=android.view.AbsSavedState$1@1cea46c2, 117=android.view.AbsSavedState$1@1cea46c2, 118=android.view.AbsSavedState$1@1cea46c2, 119=android.view.AbsSavedState$1@1cea46c2, 120=android.view.AbsSavedState$1@1cea46c2, 122=android.view.AbsSavedState$1@1cea46c2, 123=android.view.AbsSavedState$1@1cea46c2, 124=android.view.AbsSavedState$1@1cea46c2, 125=android.view.AbsSavedState$1@1cea46c2, 127=android.view.AbsSavedState$1@1cea46c2, 129=android.view.AbsSavedState$1@1cea46c2, 16908290=android.view.AbsSavedState$1@1cea46c2}}]}]
D/ReactNativeDebugOutput(26939): MainActivity::onResume()

Additional Information

  • React Native version: 0.33.0, 0.34.1
  • Platform(s): Android 5.1, API 22
  • Operating System: Mac OS X El Capitan 10.11.6
@sbycrosz
Copy link

I think this'll happen when you set the activity:launchMode to standard (in AndroidManifest.xml).
Try to change the launchMode to SingleTask & see if it fixes your problem.

Might be related: #7079

@igorclark
Copy link
Author

Thanks @sbycrosz! I just tried that and unfortunately it made the problem worse, it happened even on the second try after swipe-killing the app. Tried the other launchModes as well but no joy. Appreciate the input though, reading through all this helps to understand the overall Activity picture a bit better.

@fadookie
Copy link
Contributor

fadookie commented Oct 24, 2016

We were observing the exact same issue on RN 0.35.0 on every Android version we tested (4.x - 6.x) in both release and debug modes. As implied by #7079 and #8570, what's happening here is that multiple MainActivity instances are being pushed when the app backgrounds and then foregrounds again from a fresh install or upgrade. Both activities then receive AppState change events although only the top one is presenting to the user. Every time you background and foreground in this state, another MainActivity is pushed on top of the older ones. We also observed that killing and restarting the app would fix the issue until the next reinstall/upgrade.

You can see the multiple activities by dumping the activity stack. We also worked around this by setting android:launchMode="singleInstance" in our Manifest, although singleTask sounded like it would work as well.

Overall I think this is definitely a RN-level bug, as from the perspective of JS app code, you should be able to make a reasonable expectation that multiple instances of your app will not be launched inside the same Android task. At the very least I think the RN AndroidManifest.xml template should include a reasonable default set for launchMode as either singleInstance or singleTask. However this does seem like a workaround for an issue that should probably be solved comprehensively by the RN architecture in some manner.

@tepamid
Copy link
Contributor

tepamid commented Nov 18, 2016

We also face the same problem on RN 0.32 and Android 5.1. However, the issue is reproduced only on Xiaomi and DOOGEE devices, but it seems OK on Samsung.

If our app is built and run locally, the issue is not reproduced, despite debug or release mode. To reproduce the issue I have to deploy an apk to Google Play and install on a device. And after install on the first run the issue can be observed when switching between background and foreground modes.

Setting launchMode to singleInstance in AndroidManifest.xml for the MainActivity fixed the problem.
Thanks everyone for the solution.

P.S. Latest RN 0.37 has the issue.

@legendhb
Copy link

legendhb commented Dec 8, 2016

+1,RN v0.37 face the same porblem, even the empty project created by 'react-native init'.
Setting launchMode seems fixed the problem, but I doubt if any other issue would be caused.
Looking forward the official solution.

@cbrevik
Copy link
Contributor

cbrevik commented Jan 27, 2017

Basically echoing what has been said here, singleInstance fixes it. But I am unsure from reading about launchMode in Android if this has any negative consequences for RN.

Would almost be interesting to submit a PR with android:launchMode="singleInstance" as the default in the react-native init template, just to see what the core contributors has to say about this.

Interesting note from the docs:

The "singleTask" and "singleInstance" modes also differ from each other in only one respect: A "singleTask" activity allows other activities to be part of its task. It's always at the root of its task, but other activities (necessarily "standard" and "singleTop" activities) can be launched into that task. A "singleInstance" activity, on the other hand, permits no other activities to be part of its task. It's the only activity in the task. If it starts another activity, that activity is assigned to a different task — as if FLAG_ACTIVITY_NEW_TASK was in the intent.

@fadookie
Copy link
Contributor

@cbrevik Yes, a PR is a good idea, although I'm still unclear as to whether singleInstance or singleTask is a better default. singleInstance has been working well for us so far, but I wonder if there are any native libraries out there that would depend on the behavior allowed by singleTask?

@cbrevik
Copy link
Contributor

cbrevik commented Jan 30, 2017

@fadookie I've wondered about the same thing. I've tried to read up on it, but I can't find a definitive answer to that question.

Since singleTask and singleInstance achieves the same goal (only one instance of our MainActivity allowed on the device), it seems like singleTask would be a better default.

At the same time, we're probably masking an underlying problem with RN with this fix. It'd be nice to have the core contributors weigh in on this issue.

@hramos
Copy link
Contributor

hramos commented May 25, 2017

Closing this issue because it has been inactive for a while. If you think it should still be opened let us know why.

@hramos hramos closed this as completed May 25, 2017
@hramos hramos added the Icebox label May 26, 2017
@fadookie
Copy link
Contributor

fadookie commented Jun 23, 2017 via email

@facebook facebook locked as resolved and limited conversation to collaborators Jul 19, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests

8 participants