【问题标题】:Bring a singleInstance Activity Back Using a Notification使用通知恢复单实例活动
【发布时间】:2019-03-10 20:32:37
【问题描述】:

我有一个正常的Activity,我们称之为A,它是打开应用程序时呈现给用户的第一个Activity。 Activity A 有一个启动 Activity 的按钮,我们称之为 B,在清单中将 launchMode 设置为 singleInstance。 Activity B 做了一些处理。

用户可以按下主页按钮并再次打开应用程序,这将向他们显示启动活动,即活动 A。如果用户再次单击该按钮(在活动 A 中),他们将看到活动 B。在这种情况下,activity B 不会被重启,即onCreate 不会被调用,因为它是singleInstance,这正是我想要的。

我想让用户在按下主页按钮后更容易返回活动 B。因此,我创建了一个持续通知,让用户将活动 B 带回来。活动 B 完成后,正在进行的通知将被取消。

现在问题来了,单击正在进行的通知会再次重新创建活动 B,即再次调用 onCreate。我不知道为什么这里的行为与单击活动 A 上的按钮不同。这是我创建通知的方式:

Intent notifyIntent = new Intent(mContext, CallActivity.class);

PendingIntent notifyPendingIntent = PendingIntent.getActivity(
        mContext, 0, notifyIntent, PendingIntent.FLAG_NO_CREATE);

NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID)
        .setSmallIcon(R.drawable.baseline_call_white_18)
        .setContentTitle(title)
        .setContentText(text)
        .setOngoing(true)
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setContentIntent(notifyPendingIntent);

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mContext);
notificationManager.notify(NOTIFICATION_ID, builder.build());

谁能告诉我为什么这不起作用,我怎样才能让它按照我描述的方式工作?

编辑

这是我的清单的 sn-p:

<application
    android:name="com.mnm.caller.IMApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"
    tools:ignore="GoogleAppIndexingWarning">
    <activity
        android:name="com.mnm.caller.activities.SplashActivity"
        android:configChanges="orientation|keyboardHidden"
        android:noHistory="true"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme.Splash">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

    </activity>


    <activity
        android:name="com.mnm.caller.activities.LoginActivity"
        android:configChanges="orientation|keyboardHidden"
        android:theme="@style/AppTheme.NoTitleBar"
        android:screenOrientation="portrait" />

    <activity
        android:name="com.mnm.caller.activities.HomeActivity"
        android:configChanges="orientation|keyboardHidden"
        android:theme="@style/AppTheme.NoTitleBar"
        android:screenOrientation="portrait" />

    <activity
        android:name="com.mnm.caller.activities.CallActivity"
        android:configChanges="orientation|keyboardHidden"
        android:launchMode="singleInstance"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme.NoTitleBar" />


    <service
        android:name="com.mnm.caller.services.IMFirebaseMessagingService"
        android:stopWithTask="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

</application>

【问题讨论】:

  • 一般来说这种方法是错误的。特殊的启动模式singleTasksingleInstance 应该只在非常特殊的情况下使用。请发布您的清单,我可以提出替代方案。
  • @DavidWasser 我用清单更新了我的问题,请你看一下。
  • 您的单个​​实例 Activity 实际上并未在单独的任务中启动,因为您尚未在清单中指定 taskAffinity。这意味着 Android 忽略了特殊的启动模式并将其视为普通的Activity。如果您实际上启动了 2 个单独的任务,那么您会在“最近任务列表”中看到 2 个单独的条目,它们都将具有相同的名称和图标。这会让您的用户感到困惑。这些只是您不应该使用特殊启动模式singleInstancesingleTask 的部分原因。它们有很多副作用。
  • 如果用户将应用置于后台,ActivityB 在顶部,为什么用户再次启动应用时不显示ActivityB?请说明您的导航要求,也许我们可以为您提供正确的解决方案。
  • @DavidWasser 感谢您的回复。我实际上正在开发一个通话应用程序。 Activity A 是主屏幕,而 B 是调用 Activity。我想让用户在通话期间导航回主屏幕,因此我有意且有意地选择在最近的应用程序中创建该应用程序的两个实例(您可以在 Android 上的默认手机应用程序中看到确切的行为)。跨度>

标签: android android-activity android-notifications launchmode


【解决方案1】:

在你写的评论中:

我实际上正在开发一个通话应用程序。 Activity A 是主屏幕, 而 B 是调用活动。我想让用户导航回来 在通话过程中到主屏幕,所以我故意和故意 选择在最近的应用中创建应用的两个实例(可以看到 Android 上默认手机应用程序中的确切行为)

如果是这种情况,您可能确实希望有 2 个可以在它们之间切换的独立任务。为此,您需要使用taskAffinity。你的CallActivity 应该有singleTasksingleInstance 的启动模式,你应该设置android:taskAffinity="call" 或类似的东西。为了不让您的用户感到困惑,您还应该为CallActivity 提供不同的android:label 和不同的android:icon,以便当此任务出现在最近任务列表中时,它看起来与您的应用程序的其余部分不同。确保在启动 CallActivity 时还设置了 FLAG_ACTIVITY_NEW_TASK。您还应该在构建 Notification 时设置此标志。

【讨论】:

  • 我试过你的解决方案,这正是我想要的!
【解决方案2】:

在创建PendingIntent 对象之前,您需要将FLAG_ACTIVITY_SINGLE_TOP 设置为Intent 实例(在您的情况下为notifyIntent)。

换句话说:

Intent notifyIntent = new Intent(mContext, CallActivity.class).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent notifyPendingIntent = PendingIntent.getActivity(
        mContext, 0, notifyIntent, PendingIntent.FLAG_NO_CREATE);

NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, CHANNEL_ID)
        .setSmallIcon(R.drawable.baseline_call_white_18)
        .setContentTitle(title)
        .setContentText(text)
        .setOngoing(true)
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setContentIntent(notifyPendingIntent);

NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mContext);
notificationManager.notify(NOTIFICATION_ID, builder.build());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多