I developed a simple application, which demostrates some strange behaviour on Android 4.4.X devices I noticed.
Lets say I want to have 2 "main" activities, where the first says "Hello" (by starting 'HelloActivity') every second time it is resumed and the second one has android:launchMode="singleTask" android:taskAffinity=".MyAffinity"
defined. Second one is started by the first one.
My Code
Manifest is pretty simple:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="14" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.affinitylaunchmodebugtest.MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:label="HELLO"
android:name="com.example.affinitylaunchmodebugtest.HelloActivity"
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
<activity
android:label="AffinityTestActivity"
android:name="com.example.affinitylaunchmodebugtest.AffinityTestActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:launchMode="singleTask"
android:taskAffinity=".MyAffinity">
</activity>
</application>
MainActivity starts AffinityTestActivity on button click and logs its lifecycle. It also starts HelloActivity every second time it is resumed:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
System.out.println(this+" onCreate");
super.onCreate(savedInstanceState);
Button b = new Button(MainActivity.this);
b.setText("START AFFINITY TEST ACTIVITY");
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println(this+" starts "+AffinityTestActivity.class.getSimpleName());
Intent intent = new Intent(MainActivity.this, AffinityTestActivity.class);
startActivity(intent);
}
});
setContentView(b);
}
private boolean skipHello = true;
@Override
protected void onResume() {
System.out.println(this+" onResume");
super.onResume();
if (!skipHello) {
System.out.println(this+" starts "+HelloActivity.class.getSimpleName());
Intent intent = new Intent(MainActivity.this, HelloActivity.class);
startActivity(intent);
skipHello = true;
} else {
skipHello = false;
}
}
@Override
protected void onPause() {
System.out.println(this+" onPause");
super.onPause();
}
@Override
protected void onDestroy() {
System.out.println(this+" onDestroy");
super.onDestroy();
}
}
AffinityTestActivity calls finish() on button click and logs its lifecycle:
public class AffinityTestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
System.out.println(this+" onCreate");
super.onCreate(savedInstanceState);
Button b = new Button(AffinityTestActivity.this);
b.setText("FINISH");
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
System.out.println(this+" finishes");
finish();
}
});
setContentView(b);
}
@Override
protected void onResume() {
System.out.println(this+" onResume");
super.onResume();
}
@Override
protected void onPause() {
System.out.println(this+" onPause");
super.onPause();
}
@Override
protected void onDestroy() {
System.out.println(this+" onDestroy");
super.onDestroy();
}
}
HelloActivity is the same as AffinityTestActivity in fact - it only has button to call finish() and printlns to log its lifecycle.
Test Scenario
- Start MainActivity.
- Start AffinityTestActivity.
- Finish AffinityTestActivity (as AffinityTestActivity finishes, MainActivity is resumed and HelloActivity is started).
- Analyze output.
Logs
Android 4.4.2 and 4.4.3: (tested on Nexus 7 II and Samsung Galaxy S5) As you can see, log ends with HelloActivity's onPause, which does not make sense (HelloActivity is displayed at top in step 3). Also AffinityTestActivity is not destroyed and MainActivity is not paused.
06-20 11:13:20.547: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onCreate
06-20 11:13:20.557: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onResume
06-20 11:13:25.371: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity$1@41f6e5c0 starts AffinityTestActivity
06-20 11:13:25.581: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onPause
06-20 11:13:25.591: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity@41f6a480 onCreate
06-20 11:13:25.611: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity@41f6a480 onResume
06-20 11:13:36.452: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity$1@41f1ede8 finishes
06-20 11:13:36.662: I/System.out(18650): com.example.affinitylaunchmodebugtest.AffinityTestActivity@41f6a480 onPause
06-20 11:13:36.682: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 onResume
06-20 11:13:36.682: I/System.out(18650): com.example.affinitylaunchmodebugtest.MainActivity@41f17e50 starts HelloActivity
06-20 11:13:36.782: I/System.out(18650): com.example.affinitylaunchmodebugtest.HelloActivity@41f8dbb8 onCreate
06-20 11:13:36.802: I/System.out(18650): com.example.affinitylaunchmodebugtest.HelloActivity@41f8dbb8 onResume
06-20 11:13:36.852: I/System.out(18650): com.example.affinitylaunchmodebugtest.HelloActivity@41f8dbb8 onPause
Older Android versions (<4.4.2, tested on 2.3.5., 4.1.2 and 4.2.1 devices, 4.0.3 emulator) work as expected - HelloActivity is not paused after onResume and AffinityTestActivity is destroyed:
06-20 11:16:30.867: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onCreate
06-20 11:16:30.907: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onResume
06-20 11:16:34.157: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity$1@40f9b350 starts AffinityTestActivity
06-20 11:16:34.277: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onPause
06-20 11:16:34.297: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onCreate
06-20 11:16:34.357: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onResume
06-20 11:16:38.687: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity$1@40fad640 finishes
06-20 11:16:38.707: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onPause
06-20 11:16:38.717: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onResume
06-20 11:16:38.717: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 starts HelloActivity
06-20 11:16:38.747: I/System.out(3296): com.example.affinitylaunchmodebugtest.MainActivity@40f998b0 onPause
06-20 11:16:38.777: I/System.out(3296): com.example.affinitylaunchmodebugtest.HelloActivity@40fbdd48 onCreate
06-20 11:16:38.827: I/System.out(3296): com.example.affinitylaunchmodebugtest.HelloActivity@40fbdd48 onResume
06-20 11:16:39.877: I/System.out(3296): com.example.affinitylaunchmodebugtest.AffinityTestActivity@40fab810 onDestroy
My Question(s)
- Why is my HelloActivity paused on Android 4.4.X devices right after it is started and displayed at top?
- How can I avoid it and force the application to have "normal" activity lifecycle, as older Android versions (<4.4.2) do?
I develop application, which is much more complex and works with lifecycle of its activities and this behaviour is violating my application's functionality.
Thank you very much!