Android同Activity多实例问题:FCM消息触发Chat Activity状态判断与处理
解决FCM消息触发Chat Activity的三种状态处理逻辑
我来帮你捋清楚这个需求的实现思路,核心就是精准判断目标Chat Activity的当前状态,然后对应不同的启动和传参策略,咱们一步步来:
第一步:实现Activity状态跟踪工具类
首先得能知道Chat Activity到底是没运行、在后台还是在前台,咱们可以通过Application.ActivityLifecycleCallbacks来全局监听Activity的生命周期:
class AppLifecycleManager private constructor() : Application.ActivityLifecycleCallbacks { // 保存当前处于前台的Activity(弱引用避免内存泄漏) private var currentForegroundActivity: WeakReference<Activity>? = null // 保存所有已启动的Activity类集合 private val runningActivities = mutableSetOf<Class<out Activity>>() companion object { val instance: AppLifecycleManager by lazy { AppLifecycleManager() } } override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { runningActivities.add(activity.javaClass) } override fun onActivityStarted(activity: Activity) {} override fun onActivityResumed(activity: Activity) { currentForegroundActivity = WeakReference(activity) } override fun onActivityPaused(activity: Activity) { if (currentForegroundActivity?.get() == activity) { currentForegroundActivity = null } } override fun onActivityStopped(activity: Activity) {} override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} override fun onActivityDestroyed(activity: Activity) { runningActivities.remove(activity.javaClass) } // 判断【指定用户】的ChatActivity是否在前台 fun isTargetChatForeground(targetUserId: String): Boolean { val foregroundActivity = currentForegroundActivity?.get() return foregroundActivity is ChatActivity && foregroundActivity.targetUserId == targetUserId } // 判断【指定用户】的ChatActivity是否已启动(后台/前台) fun isTargetChatRunning(targetUserId: String): Boolean { if (!runningActivities.contains(ChatActivity::class.java)) return false // 这里可以扩展:遍历任务栈或通过全局缓存,确认是否存在对应用户的ChatActivity实例 return true } }
然后在你的Application类里注册这个监听:
class MyApp : Application() { override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(AppLifecycleManager.instance) } }
第二步:在FCM消息接收中处理三种状态
在FirebaseMessagingService的onMessageReceived方法里,解析消息中的用户信息,然后判断状态并处理:
class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 解析消息中的关键数据:目标用户ID、消息内容 val targetUserId = remoteMessage.data["target_user_id"] ?: return val messageContent = remoteMessage.data["message_content"] ?: return val lifecycleManager = AppLifecycleManager.instance when { // 情况1:对应用户的ChatActivity未运行 !lifecycleManager.isTargetChatRunning(targetUserId) -> { val intent = Intent(this, ChatActivity::class.java).apply { putExtra("TARGET_USER_ID", targetUserId) putExtra("NEW_MESSAGE", messageContent) // Service中启动Activity必须加这个flag addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } startActivity(intent) } // 情况2:对应用户的ChatActivity在后台 !lifecycleManager.isTargetChatForeground(targetUserId) -> { val intent = Intent(this, ChatActivity::class.java).apply { putExtra("TARGET_USER_ID", targetUserId) putExtra("NEW_MESSAGE", messageContent) // 将后台的Activity调到前台,不会新建实例 addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_NEW_TASK) } startActivity(intent) } // 情况3:对应用户的ChatActivity在前台 else -> { // 直接给前台的ChatActivity发消息,这里用LiveData举例,也可以用EventBus/接口回调 ChatActivity.targetMessageLiveData.postValue(messageContent) } } } }
第三步:ChatActivity中处理消息接收
在ChatActivity里,要处理启动时的参数,以及前台实时消息:
class ChatActivity : AppCompatActivity() { // 用于前台接收消息的LiveData companion object { val targetMessageLiveData = MutableLiveData<String>() } lateinit var targetUserId: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_chat) // 接收启动时传递的参数 targetUserId = intent.getStringExtra("TARGET_USER_ID") ?: "" intent.getStringExtra("NEW_MESSAGE")?.let { // 处理启动时带来的新消息 addMessageToChatUI(it) } // 监听前台实时消息 targetMessageLiveData.observe(this) { newMessage -> addMessageToChatUI(newMessage) } } // 自定义方法:更新聊天UI private fun addMessageToChatUI(message: String) { // 这里实现你的具体UI逻辑,比如往RecyclerView添加消息项 } override fun onDestroy() { super.onDestroy() // 移除观察者避免内存泄漏 targetMessageLiveData.removeObservers(this) } }
一些实用细节
- 如果需要严格区分特定用户的ChatActivity(比如用户x和y的聊天页,而非其他用户),可以在
isTargetChatRunning里扩展逻辑:比如用全局Map缓存每个ChatActivity实例对应的用户ID,或者通过ActivityManager遍历任务栈确认。 - 前台传递消息的方式,选你项目里常用的即可:LiveData适合Jetpack架构项目,EventBus适合跨组件通信场景,接口回调则更轻量化。
内容的提问来源于stack exchange,提问作者Rad
相关产品推荐
相关产品推荐

