Android:从通知启动Activity时如何跳过后台最近Activity的onResume?
嘿,这个问题我之前做项目的时候也碰到过,简直太头疼了!咱们来一步步拆解解决它~
问题根源分析
你当前遇到的情况,核心原因是:当应用处于后台时,系统收到通知点击事件后,会先把应用的现有任务栈带到前台,这就会触发栈顶Activity的onResume()方法;之后才会处理你PendingIntent里指定的目标Activity启动逻辑。而你用的FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_SINGLE_TOP,只有当目标Activity已经在现有任务栈中时,才会清除它上方的Activity并唤醒它,否则只会创建新的目标Activity实例,无法阻止原栈顶Activity被唤醒执行onResume()。
推荐解决方案:透明中转Activity
这个方法可以完美绕过原栈顶Activity的唤醒逻辑,且不会影响用户体验,也不需要修改原有Activity的代码逻辑。
1. 创建透明中转Activity
首先新建一个无UI的透明Activity,用来作为通知点击的中转入口:
- 先在
AndroidManifest.xml中注册这个Activity,指定透明主题:
<activity android:name=".TransparentNotificationActivity" android:theme="@style/TransparentActivityTheme" android:exported="false" />
- 在
styles.xml中定义透明主题:
<style name="TransparentActivityTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowContentOverlay">@null</item> <item name="android:windowNoTitle">true</item> <item name="android:backgroundDimEnabled">false</item> </style>
2. 修改PendingIntent创建逻辑
把原来直接启动目标Activity的逻辑,改成先启动这个透明中转Activity,并把通知携带的参数传递过去:
PendingIntent createContentIntent(Context appContext, NotificationData data) { // 先创建中转Activity的Intent Intent transitIntent = new Intent(appContext, TransparentNotificationActivity.class); Bundle extras = createBundle(); extras.putSerializable(EXTRA_NOTIFICATION_DATA, data); transitIntent.putExtras(extras); // 设置FLAG确保中转Activity在新任务栈启动,避免唤醒原栈 transitIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // 使用FLAG_UPDATE_CURRENT保证参数能正确更新 return PendingIntent.getActivity( appContext, data.hashCode(), // 用data的哈希值作为requestCode,避免PendingIntent复用冲突 transitIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE ); }
3. 中转Activity的逻辑实现
在透明Activity的onCreate()方法中,直接取出参数启动目标Activity,然后立即finish自己(用户完全看不到这个过程):
public class TransparentNotificationActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 获取通知携带的数据 NotificationData data = (NotificationData) getIntent().getSerializableExtra(EXTRA_NOTIFICATION_DATA); if (data != null) { // 创建目标Activity的Intent Intent targetIntent = createNotificationIntent(this, data); if (targetIntent != null) { // 把中转的参数传递给目标Activity targetIntent.putExtras(getIntent().getExtras()); // 启动目标Activity startActivity(targetIntent); } } // 立即finish,用户无感知 finish(); } }
其他可选方案(按需选择)
如果你的业务场景可以接受清空原有任务栈,也可以直接修改Intent的Flags:
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
这个Flags会直接清空应用的现有任务栈,然后启动目标Activity,原栈顶Activity会被直接销毁,自然不会执行onResume()。但缺点是会丢失用户之前的页面状态,需要根据业务场景判断是否适用。
内容的提问来源于stack exchange,提问作者Martinu

