安卓:为什么点击带有后退堆栈的意图通知会销毁父级MainActivity?

6
以下是我的sendNotification函数,它将从一个服务中调用,目前它可以创建通知并在状态栏上显示。但是当应用已经运行(我在MainActivity),点击通知以打开ConversActivity时,父级MainActivity被销毁,当我从ConversActivity按返回按钮时,MainActivity被重新创建。请帮助我避免此行为发生(无论应用是否在前台/后台运行)。
顺带一提,在应用程序被杀死或未运行时,这是正确的行为,因为MainActivity是从返回堆栈中创建的,这是正确的。但是当应用正在运行时,为什么MainActivity会被销毁和重新创建呢?这不是高效的,并且由于从MainActivity的onCreate启动应用程序而导致应用程序变慢。
提前感谢您的帮助和支持。
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 (返回按钮):
@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());
}

你有检查过当你将ConversActivity移动到MainActivity时,你的MainActivity应该在onResume中出现而不是onCreate吗? - Mahi
是的,我在MainActivity的onCreate和onDestroy中放置了Log.d和debug。当我点击通知时,我看到onDestroy被触发,然后当我从ConversActivity点击返回按钮时,onCreate再次被触发。我的返回堆栈和pendingIntent可能有问题吗? - hemlk
2个回答

14

查看源代码,似乎TaskStackBuilder会向根Activity Intent添加以下标志:

    intents[0].addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
            IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
            IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
如果您阅读了有关如何设置用户预期导航行为以进行通知的文档,似乎他们希望您创建一个“新任务”,其中包含您正在启动的Activity和适当的后退堆栈,以便用户能够通过“全新”的应用程序副本返回到主屏幕。恐怕taskAffinity的标准行为可能会使保留原始应用程序的任务并从通知启动另一个任务变得不可能。这也许不是您想要的。
发生的情况是,如果您的应用正在运行并单击通知,则会将现有任务带到前台,清除(所有Activity都已完成/销毁),然后将最高层的Activity(在您的情况下为ConversActivity)启动到此任务中。然后设置后退堆栈,以便如果用户单击“返回”,它将逐个重新创建后退堆栈中的先前Activity,直到用户最终到达主屏幕。
上面的内容应该解释了正在发生的事情及其原因。
要解决您的问题,我建议您执行以下操作:
不要为通知设置后退堆栈。只需让通知启动ConversActivity
ConversActivity.onCreate()中执行以下操作:
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;
}

如果您的应用程序已经打开,这应该只会在其上启动ConversActivity,并且如果您的应用程序未运行,则应以正确的后退堆栈启动它。


1
哇塞,我太高兴了,这对我来说完全有效,非常感谢你!=)) - hemlk

0
如果您的主活动未运行,则通知数据将传递到主活动,然后您可以将数据从主活动传递到对话活动。如果主活动正在运行,则数据将直接传递到对话活动。
 public class MainActivity extends Activity

 {
  public static boolean isMainActivityRunning;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
}

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();

    isMainActivityRunning = true;
}

@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();

    isMainActivityRunning = false;
}
}

在你的PendingIntent中做一些更改

 NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
 Intent intent=null;
 if(!MainActivity.isMainActivityRunning){
 intent = new Intent(context, MainActivity.class);
 }
else{
 intent = new Intent(context, ConversActivity.class);
 }

intent.putExtra("dname", dname);
int requestID = (int) System.currentTimeMillis();
PendingIntent mContentIntent = PendingIntent.getActivity(mContext,
                    requestID , intent , Intent.FILL_IN_ACTION);

但是当我这样做时,我失去了我的后退堆栈,在应用程序运行时这是可以的。但是当应用程序被杀死(或者当我从MainActivity内部按下Back按钮时),然后从ConversActivity按下Back按钮将直接返回到主屏幕。(发送通知是从服务中调用的) - hemlk
嗨Montu,不知何故isMainActivityRunning总是对我返回false,请注意我正在从服务中运行sendNotification,并且传递给sendNotification的上下文来自[getApplicationContext()]。我从MainActivity中添加了isMainActivityRunning的watch,它返回true,但是sendNotification的Log.d始终显示isMainActivityRunning的“false”。从服务获取isMainActivityRunning的值有问题。 - hemlk
你是在onResume之前启动服务吗?因为isMainActivityRunning的值在这个方法中是true。 - Mahi
我在MainActivity的onstart中开始了我的服务,此时所有身份验证都已通过。顺便说一句,我得到了David的解决方案。虽然如此,非常感谢你的帮助 =)) - hemlk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接