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

点击短信通知时,如何避免重复打开已启动的ReceivedMessageActivity

我来帮你解决这个问题,你需要结合Activity启动模式、Intent Flags和PendingIntent的正确配置来实现需求,具体步骤如下:

1. 配置ReceivedMessageActivity的启动模式

首先在AndroidManifest.xml中修改ReceivedMessageActivity的属性,确保它在任务栈中只会存在一个实例,并且归属于应用默认任务栈:

<activity
    android:name=".ReceivedMessageActivity"
    android:launchMode="singleTask"
    android:taskAffinity="${applicationId}"
    android:excludeFromRecents="false">
    <!-- 添加自定义Intent Filter,避免和其他Intent冲突 -->
    <intent-filter>
        <action android:name="com.yourpackage.action.OPEN_RECEIVED_MESSAGE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

这里singleTask模式保证整个任务栈中只会有一个该Activity的实例,taskAffinity确保它在应用自己的任务栈中运行。

2. 构建通知的PendingIntent

在SMSReceiver中创建通知时,需要构建能正确复用Activity实例的Intent,并设置合适的Flags:

// 构建打开ReceivedMessageActivity的Intent
Intent intent = new Intent("com.yourpackage.action.OPEN_RECEIVED_MESSAGE");
intent.setPackage(context.getPackageName()); // 明确指向本应用,避免歧义

// 设置关键Intent Flags:
// FLAG_ACTIVITY_NEW_TASK:从BroadcastReceiver启动Activity必须添加
// FLAG_ACTIVITY_CLEAR_TOP:如果Activity已存在,清除它上方的所有Activity,将其带到前台
// FLAG_ACTIVITY_SINGLE_TOP:如果Activity已在栈顶,直接调用onNewIntent()而非新建实例
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

// 传递短信数据(可选)
intent.putExtra("sms_sender", smsSender);
intent.putExtra("sms_content", smsContent);

// 构建PendingIntent,Android 12+必须指定IMMUTABLE/MUTABLE
PendingIntent pendingIntent = PendingIntent.getActivity(
    context,
    0, // requestCode,可根据需求设置不同值区分通知
    intent,
    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);

// 创建并发送通知
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, YOUR_NOTIFICATION_CHANNEL_ID)
    .setSmallIcon(R.drawable.ic_sms_notification)
    .setContentTitle("新短信")
    .setContentText(smsSender + ": " + smsContent)
    .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    .setContentIntent(pendingIntent)
    .setAutoCancel(true);

NotificationManagerCompat.from(context).notify(SMS_NOTIFICATION_ID, builder.build());

3. 处理ReceivedMessageActivity的onNewIntent()

因为设置了singleTask模式,当Activity已存在时,系统会调用onNewIntent()而非onCreate(),你需要在这里更新UI并将Activity调至前台:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    // 更新Intent,确保后续getIntent()能拿到最新数据
    setIntent(intent);
    // 处理新短信数据,更新UI
    String sender = getIntent().getStringExtra("sms_sender");
    String content = getIntent().getStringExtra("sms_content");
    updateMessageDisplay(sender, content);
    // 将Activity所在任务栈调至前台
    moveTaskToFront(getTaskId(), 0);
}

// 自定义方法:更新短信显示UI
private void updateMessageDisplay(String sender, String content) {
    tvSender.setText(sender);
    tvContent.setText(content);
    // 可添加滚动到顶部等交互逻辑
}

4. 权限与广播接收器注意事项

  • 确保在AndroidManifest.xml中声明短信相关权限:
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ 必需 -->
    
  • 静态注册的SMSReceiver在Android 8.0+仍可接收短信广播,但建议在应用启动时动态注册,避免后台限制影响。

场景验证

  • 应用未运行:点击通知会创建新的任务栈并启动ReceivedMessageActivity
  • 应用运行且Activity已打开:直接复用现有实例,调用onNewIntent()更新UI并调至前台,不会创建新实例
  • 应用运行但Activity未打开:会创建ReceivedMessageActivity的新实例(符合singleTask模式逻辑)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:20:18