Up Navigation not launching parent activity

2019-02-25 19:42发布

问题:

I have two activities A and B where A is the parent of B. Now I show a notification that launches B. when I tap on the notification, B launches. Then I click on the up button. It works finr when activity A is in the backstack but otherwise the app Just closes and does not launch activity A.

My Setup.

I have declared A as Parent of B in Manifest with A in SingleTop launchMode

<activity
        android:name=".A"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:launchMode="singleTop"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>
            <action android:name="<packegeName>.Home" />
        </intent-filter>
    </activity>
    <activity
        android:name=".B"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:parentActivityName=".A"
        android:theme="@style/AppTheme.NoActionBar">
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".A" />
    </activity>

This is the notification Intent :

Intent intent = new Intent(this, B.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 
                                                        PendingIntent.FLAG_ONE_SHOT);

In Activity B :

@Override
public void onCreate(Bundle savedInstanceState) {
    ....
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    ....
}

What I've tried

In order to debug I've tried manually triggering this up navigation in Activity B's onResume, with all of these :

1)

Intent upIntent = NavUtils.getParentActivityIntent(this);
upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    // This activity is NOT part of this app's task, so create a new task
    // when navigating up, with a synthesized back stack.
    TaskStackBuilder.create(this)
            // Add all of this activity's parents to the back stack
            .addNextIntentWithParentStack(upIntent)
            // Navigate up to the closest parent
            .startActivities();
} else {
    // This activity is part of this app's task, so simply
    // navigate up to the logical parent activity.
    NavUtils.navigateUpTo(this, upIntent);
}

2)

onNavigateUp();

3)

NavUtils.navigateUpFromSameTask(this);

But none of these seem to work when Activity A is not in the Backstack, the app just exits.

I have scoured SO and Google (even bing!) looking for an answer and tried everything I could find to no avail. As there is no error or log output, I also have no idea how to debug this.

Any solution or tips on finding out the issue will be greatly appreciated.

Thanks.

回答1:

Try the approach described for Synthesize a new Back Stack for Deep Links

You will have use TaskStackBuild to build the back stack and get the PendingIntent when starting on Activity B.

Check this video from Android Design Patterns explains it simple.



回答2:

@pablobu's answer worked for me but I want to add a little more explanation of what I found.

Damn those docs are confusing

Where I initially got confused was due to this :

If your activity provides any intent filters that allow other apps to start the activity, you should implement the onOptionsItemSelected() callback such that if the user presses the Up button after entering your activity from another app's task, your app starts a new task with the appropriate back stack before navigating up.

    if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
        // This activity is NOT part of this app's task, so create a new task
        // when navigating up, with a synthesized back stack.
        TaskStackBuilder.create(this)
                // Add all of this activity's parents to the back stack
                .addNextIntentWithParentStack(upIntent)
                // Navigate up to the closest parent
                .startActivities();
    } else {
        // This activity is part of this app's task, so simply
        // navigate up to the logical parent activity.
        NavUtils.navigateUpTo(this, upIntent);
    }

I was of the impression that this would generate the backstack for me. But there is a difference.

NavUtils.shouldUpRecreateTask(this, upIntent) will return true only if the current activity is inside another app's task. As for launching from a notification, this will be false, so the task-stack-building code does not execute.

The correct way, is to build the backstack when generating the notification and passing it as a pending intent. From this page :

when a notification takes the user to an activity deep in your app hierarchy, you can use this code to create a PendingIntent that starts an activity and inserts a new back stack into the target task.

Intent detailsIntent = new Intent(this, DetailsActivity.class);
// Use TaskStackBuilder to build the back stack and get the PendingIntent
PendingIntent pendingIntent =
        TaskStackBuilder.create(this)
                        // add all of DetailsActivity's parents to the stack,
                        // followed by DetailsActivity itself
                        .addNextIntentWithParentStack(detailsIntent)
                        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(pendingIntent);