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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:34:03