Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: Why clicking on notification of intent with backstack destroys parent MainActivity?

Below is my sendNotification function which will be called from a Service, it's working fine creating a notification and showing it on the status bar. But when the app is already running (I'm at MainActivity),clicking on the notification to open ConversActivity, the parent MainActivity is destroyed, and when im pressing back button from ConversActivity, MainActivity is recreated. Please help me to avoid this behavior when the app is running (either in fore/background)

Btw, this is the correct behaviour when the app is killed or not running, coz MainActivity is created from the backstack, which is correct. But when the app is running, why MainActivity is destroyed and re-created? This is not efficient and cause slowness to the app due to app initiation from MainActivity 's onCreate.

Thanks in advance & Best Regards.

AndroidManifest.xml:

<activity
        android:name=".View.MainActivity"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="stateHidden"
        android:launchMode="singleTop"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:theme="@android:style/Theme.Black.NoTitleBar" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>


<activity
        android:name=".View.ConversActivity"
        android:label="@string/title_activity_convers"
        android:parentActivityName=".View.MainActivity"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="stateHidden|adjustResize" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".View.MainActivity"/>
</activity>

-

ConversActivity.java (back button):

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    switch (item.getItemId()) {
        case android.R.id.home:
            //onBackPressed();
            //finish();
            NavUtils.navigateUpFromSameTask(this);
            return true;
        case R.id.action_settings:
            return true;
    }
    return super.onOptionsItemSelected(item);
}

-

public static void sendNotification(Context context, String dname) {
    NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    Intent intent = new Intent(context, ConversActivity.class);
    intent.putExtra("dname", dname);

    PendingIntent pendingIntent = TaskStackBuilder.create(context)
                    // add all of DetailsActivity's parents to the stack,
                    // followed by DetailsActivity itself
                    .addNextIntentWithParentStack(intent)
                    .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

    NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(context)
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setContentTitle("You've got a message!")
                    .setStyle(new NotificationCompat.BigTextStyle().bigText("@" + dname + ": " + msg))
                    .setContentText("@" + dname + ": " + msg)
                    .setAutoCancel(true)
                    .setVibrate(new long[]{100, 100}) //off-on-off-on-off
                    .setLights(Color.GREEN, 3000, 3000)
                    .setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
    ;
    mBuilder.setContentIntent(pendingIntent);
    mNotificationManager.notify(dname, 0, mBuilder.build());
}
like image 315
hemlk Avatar asked Dec 12 '14 10:12

hemlk


1 Answers

Looking at the source code, it looks like TaskStackBuilder adds the following flags to the root Activity Intent:

    intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
            IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
            IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);

If you read the documentation about how to set up the user's expected navigation behaviour for Notifications, it seems that what they want you to do is have the Notification create a "fresh task" which will contain the Activity you are launching and an appropriate back-stack so that the user will be able to back up through a "fresh" copy of your application back to the HOME screen. I'm afraid that the standard behaviour of taskAffinity is liable to make it impossible to preserve your original app's task and also start another one from the Notification. That may not be what you want anyway.

What is happening here is that, if your app is running and you click on the Notification, the existing task is being brought to the foreground, cleared (all Activities are finished/destroyed) and then the topmost Activity is launched into this task (in your case ConversActivity). The back stack is then set up so that if the user clicks BACK, it will recreate the previous Activities in the back stack, one at a time, until the user ends up at the HOME screen.

The above should explain what is happening and why.

To solve your problem, I'd suggest that you do the following:

Do not setup the backstack for the Notification. Just have the Notification launch ConversActivity.

In ConversActivity.onCreate() do the following:

super.onCreate(...);
if (isTaskRoot()) {
    // Started from a Notification and the app is not running, restart the app with back stack
    // Here create a launch Intent which includes the back stack
    Intent intent = new Intent(this, ConversActivity.class);
    // Copy extras from incoming Intent
    intent.putExtras(getIntent());
    // Now launch this activity again and immediately return
    TaskStackBuilder.create(this)
        .addNextIntentWithParentStack(intent)
        .startActivities();
    return;
}

This should just launch ConversActivity on top of your existing app (if it is open), and should launch it with the correct back stack if your app is not running.

like image 164
David Wasser Avatar answered Nov 14 '22 23:11

David Wasser