Android does not reuse main activity and starts mu

2019-08-07 12:15发布

问题:

I have an application with only one activity.In the onCreate I am showing a notification, on whose click I show my activity, reusing it if necessary ( or so I thought ) The code is:

package com.example.multiplestartupifusingpendingintent;

import android.app.Activity;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

    public static final String TAG = "hexor";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.d(TAG,
                "onCreate " + getClass().getSimpleName()
                        + Integer.toHexString(hashCode()));

        NotificationManager notifMgr = (NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE);
        showReuseNotification(notifMgr);
    }

    private void showReuseNotification(NotificationManager notifMgr) {
        Intent reuseIntent = new Intent(this, MainActivity.class);
        reuseIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                | Intent.FLAG_ACTIVITY_SINGLE_TOP);

        PendingIntent reusePendingIntent = PendingIntent.getActivity(this, 2,
                reuseIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        Notification.Builder builder = new Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentIntent(reusePendingIntent)
                .setContentTitle("Resue from memory");

        notifMgr.notify(2, builder.build());
    }

    @Override
    protected void onDestroy() {

        Log.d(TAG,
                "onDestroy " + getClass().getSimpleName()
                        + Integer.toHexString(hashCode()));
        super.onDestroy();
    }
}

The manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.multiplestartupifusingpendingintent"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.multiplestartupifusingpendingintent.MainActivity"
            android:configChanges="orientation|screenSize"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

My problem is a behavior happening, that I don't understand:

  1. If I start the application (first onCreate call ), then put it to backround, then click on its desktop icon, the same instance is reused. In logcat I can see just 1 onCreate call. It is what I want

  2. If I start the application ( first onCreate call ), put it to background, click the notification , then click the desktop icon ( second onCreate call ) , then I see 2 onCreate calls in logcat. As I press back I go twice before I can exit the app, and normally I see 2 onDestroy calls, since I have 2 identical stacked activities.

Why is the last behavior happening? Why is Android not reusing the existing activity, and creates 2 copies of them stacked? More weird, why is it doing only in case 2/why is it not doing it in case 1 also?

Thanks

回答1:

In the first case you comment, your activity is paused and has not been destroyed, so it moves from paused state to resumed state. You may check the activity lifecycle to learn more about it.

You should set

android:launchMode="singleInstance"

to your activity (in the manifest) and receive new intents inside:

  • onCreate(...) in case the activity has been destroyed
  • onNewIntent(...) in case the activity is paused/resumed

Hope it helps.



回答2:

If you only have a single Activity, you should be able to do this in showReuseNotification():

    Intent reuseIntent = new Intent(this, MainActivity.class);
    reuseIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent reusePendingIntent = PendingIntent.getActivity(this, 2,
            reuseIntent, PendingIntent.FLAG_UPDATE_CURRENT);

This will bring an existing instance of your application to the foreground (if there is one), or start a new one (if there isn't already an active one).



回答3:

In the second case, your activity is still visible, but not in the foreground, because the notification bar uses the trick of stacking its own transparent activity on top of the second activity to make it appear as if a status bar was getting pulled down on top of the Activity.

And because of this special case, Android assigns a different priority to the activity underlying that foreground activity.

Let me look for a reference to what I'm saying. I'll be back soon.