You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Jetpack Compose单Activity应用:通知跳转避免Activity重启问题

问题

在Jetpack Compose单Activity应用中,我想通过通知操作按钮跳转到指定页面。参考官方文档采用Deep Link导航后,发现点击通知按钮时,即使Activity在后台运行,仍会被重启后再跳转到目标页面。以下是我的实现代码:

Manifest.xml配置

<activity
    android:name=".ui.AppActivity"
    android:launchMode="standard"
    android:exported="true">
    <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter>
         <action android:name="android.intent.action.VIEW" />
         <category android:name="android.intent.category.DEFAULT" />
         <category android:name="android.intent.category.BROWSABLE" />
         <data android:scheme="myApp" android:host="screenRoute" />
    </intent-filter>
</activity>

根导航图Deep Link声明

composable(
   route = "screenRoute",
   deepLinks = listOf(navDeepLink { uriPattern = "myApp://screenRoute" })
) {
   ComposableScreen()
}

通知Pending Intent实现

val intent = Intent().apply {
    action = Intent.ACTION_VIEW
    data = "myApp://screenRoute".toUri()
}

val deepLinkPendingIntent = TaskStackBuilder.create(context).run {
    addNextIntentWithParentStack(intent)
    getPendingIntent(1234, FLAG_UPDATE_CURRENT)
}

我原以为是自己实现有误,但下载官方Compose导航Codelabs测试后,发现通过Intent触发Deep Link时同样会重启Activity。因此有以下疑问:

  1. 单Activity应用中,能否通过Deep Link从通知跳转页面且不重启Activity?
  2. 若不可行,该如何实现无重启的通知跳转指定Composable页面?是否需通过广播实现?
  3. Deep Link导致Activity重启是否因为它是主启动Activity?

回答

问题1:可以实现不重启Activity的Deep Link跳转

核心是调整Activity启动模式和Intent标记,同时避免TaskStackBuilder的不当使用:

  • 将Activity的launchMode改为singleTop(单Activity场景下更合适,singleTask也可但会影响任务栈整体结构),这样Activity在栈顶时不会创建新实例,而是触发onNewIntent()方法。
  • 给Intent添加FLAG_ACTIVITY_SINGLE_TOP标记,确保栈顶存在目标Activity时直接复用;若需要清除目标页面之上的栈元素,可再加FLAG_ACTIVITY_CLEAR_TOP。
  • 不要用TaskStackBuilder.addNextIntentWithParentStack(),这个方法会强制构建任务栈,反而容易触发Activity重启,直接创建PendingIntent即可。

修改后的Pending Intent代码:

val intent = Intent(context, AppActivity::class.java).apply {
    action = Intent.ACTION_VIEW
    data = "myApp://screenRoute".toUri()
    flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
}

val deepLinkPendingIntent = PendingIntent.getActivity(
    context,
    1234,
    intent,
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // Android 12+必须添加FLAG_IMMUTABLE
)

同时在Activity中重写onNewIntent(),把新Intent传递给NavHostController:

override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    navController.handleDeepLink(intent)
}

问题2:无需广播,用调整后的Deep Link或自定义Action即可

除了优化后的Deep Link,也可以用自定义Action+Intent的方式,更适合纯内部跳转:

  • 给Intent设置自定义Action,比如"com.myapp.action.OPEN_SCREEN_ROUTE"
  • 在Activity的onNewIntent()中判断Action,直接调用navController.navigate("screenRoute")
  • 构建PendingIntent时使用这个自定义Action的Intent,同样加上FLAG_ACTIVITY_SINGLE_TOP标记

这种方式不需要处理Uri解析,逻辑更直接。

问题3:Activity重启和它是主启动Activity无关

核心原因有两个:

  1. 默认的standard启动模式会每次创建新的Activity实例,不管后台是否已有实例。
  2. TaskStackBuilder.addNextIntentWithParentStack()会强制按照任务栈规则重建Activity,忽略后台已有实例的状态。
    只要调整启动模式和Intent标记,主启动Activity也能实现无重启跳转。

内容的提问来源于stack exchange,提问作者Maxime C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:25:31