android – Bug: onNewIntent not called for singleTop activity with Intent.FLAG_ACTIVITY_NEW_TASK-ThrowExceptions

Exception or error:

There appears to be a bug in startActivity.

By setting activities to be singleTop with different taskAffinity in AndroidManifest.xml and using the Intent.FLAG_ACTIVITY_NEW_TASK when calling startActivity, two activities can be created in two tasks (one activity per task).

Calling startActivity again will return to the first activity/task and onNewIntent is called. However, calling startActivity a forth time will return to the second activity/task, but onNewIntent is not called.

The only difference between the two tasks is their taskAffinity. Somehow, asymmetrical behaviour is observed.

However, if the Intent.FLAG_ACTIVITY_SINGLE_TOP is also used, then onNewIntent is called as expected.

It would appear that singleTop in AndroidManifest.xml is not the same as Intent.FLAG_ACTIVITY_SINGLE_TOP in the Intent.

public class ActivityA extends Activity implements OnClickListener {
    private String tag;

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        tag = getClass().getName();
        Log.v(tag, "onCreate()");

        setContentView(R.layout.main);
        Button button = (Button)findViewById(R.id.button);
        button.setText(tag.endsWith("ActivityA") ? "Activity B"
                : "Activity A");
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent;
        int flags = Intent.FLAG_ACTIVITY_NEW_TASK
        // | Intent.FLAG_ACTIVITY_SINGLE_TOP
        ;

        Log.v(tag, "onClick()");

        intent = new Intent(this,
                tag.endsWith("ActivityA") ? ActivityB.class
                        : ActivityA.class);
        intent.setFlags(flags);
        startActivity(intent);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        Log.v(tag, "onNewIntent()");
    }
}
public class ActivityB extends ActivityA {

}
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test"
    android:versionCode="1"
    android:versionName="1.0">
    <application
        android:icon="@drawable/icon"
        android:label="@string/app_name">

        <activity
            android:name=".ActivityA"
            android:launchMode="singleTop"
            android:label="Activity A">
            <intent-filter>
                <action
                    android:name="android.intent.action.MAIN" />
                <category
                    android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name=".ActivityB"
            android:launchMode="singleTop"
            android:label="Activity B"
            android:taskAffinity="activity.B">
        </activity>

    </application>
</manifest> 
How to solve:

this is a little bit late, but since i just came across this –
as Matt mentions, the flag activity single top in the manifest and in the intent are not the same (at least on previous versions of android).

in startActivityUncheckedLocked method:

on gingerbread –
https://github.com/android/platform_frameworks_base/blob/gingerbread/services/java/com/android/server/am/ActivityStack.java

look at line 2204 —

 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                                && taskTop.realActivity.equals(r.realActivity)) {

so it’s just checking the launch flags on the intent, and not checking the manifest. compare this to jellybean mr1 release:

https://github.com/android/platform_frameworks_base/blob/jb-mr1-release/services/java/com/android/server/am/ActivityStack.java

look at line 2835 —

                if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
                        || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP)
                        && taskTop.realActivity.equals(r.realActivity)) {

so it seems that in mr1, they are checking r.launchMode (presumably the AndroidManifest.xml value) in addition to the launchFlags (presumably of the intent itself), whereas in the older versions, they were only checking the intent flags.

it was actually fixed on february 16th, 2012, in this commit:
https://github.com/android/platform_frameworks_base/commit/f363dfd26c304bca33f12065a9ed3de291193962

short version is – set the single top flag in both the intent and in the manifest.

(thanks to this comment on the associated bug in the android bug tracker for pointing me to which source file to look in – http://code.google.com/p/android/issues/detail?id=4155#c9).

Leave a Reply

Your email address will not be published. Required fields are marked *