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

Kotlin类与Activity双向通信:Dialog回调如何传递至classAImpl

Kotlin单例类与Activity双向通信解决方案

问题场景

在Android开发中,Activity与Fragment可通过ViewModel或接口实现通信,但对于**单例Kotlin类(如classAImpl)与Activity(如ActivityA)**的双向通信存在以下约束:

  • classAImpl是通过依赖注入初始化的单例,负责打开ActivityA
  • ActivityA实现DialogListener接口接收Dialog的onDialogDismiss回调
  • 需求:ActivityA收到onDialogDismiss后需同步通知classAImpl,但禁止让classAImpl实现DialogListener

方案1:给单例类添加专属回调接口

在classAImpl中定义专属回调接口,让ActivityA注册该回调,在onDialogDismiss时主动触发通知,同时通过弱引用管理回调避免内存泄漏。

代码实现

1. 改造classA与classAImpl

interface classA {
    fun getData()
    fun openActivity()
    fun registerCallback(callback: ClassACallback)
    fun unregisterCallback(callback: ClassACallback)
}

// 定义classA专属回调接口
interface ClassACallback {
    fun onActivityDialogDismissed()
}

@Singleton
class classAImpl @Inject constructor(
    private val dataStoreManager: DataStoreManager,
    @ApplicationContext private val context: Context // 修正:需要ApplicationContext启动Activity
) : classA {
    // 用弱引用存储回调,避免内存泄漏
    private val callbacks = mutableSetOf<WeakReference<ClassACallback>>()

    override fun getData() {}

    override fun openActivity() {
        val intent = Intent(context, ActivityA::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) // ApplicationContext启动Activity需添加该标记
        context.startActivity(intent)
    }

    override fun registerCallback(callback: ClassACallback) {
        callbacks.add(WeakReference(callback))
    }

    override fun unregisterCallback(callback: ClassACallback) {
        callbacks.removeAll { it.get() == callback }
    }

    // 内部触发回调的统一方法
    private fun notifyDialogDismissed() {
        // 清理已被回收的弱引用
        callbacks.removeAll { it.get() == null }
        callbacks.forEach { it.get()?.onActivityDialogDismissed() }
    }
}

2. 改造ActivityA

class ActivityA : AppCompatActivity, DialogListener, ClassACallback {
    @Inject lateinit var classA: classA

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 注册回调
        classA.registerCallback(this)
    }

    override fun onDialogDismiss() {
        // 处理自身Dialog关闭逻辑
        // 同步通知classAImpl
        this.onActivityDialogDismissed()
    }

    override fun onActivityDialogDismissed() {
        // 此处可直接触发classAImpl的逻辑,或让classAImpl内部通过notifyDialogDismissed统一处理
    }

    override fun onDestroy() {
        super.onDestroy()
        // 注销回调,避免内存泄漏
        classA.unregisterCallback(this)
    }
}

方案2:使用Kotlin响应式流(SharedFlow)

利用Kotlin SharedFlow实现事件通知,ActivityA发送Dialog关闭事件,classAImpl监听并处理事件,这种方式解耦性更强,适合复杂场景。

代码实现

1. 改造classA与classAImpl

interface classA {
    fun getData()
    fun openActivity()
    val dialogDismissEvents: SharedFlow<Unit>
    fun sendDialogDismissEvent()
}

@Singleton
class classAImpl @Inject constructor(
    private val dataStoreManager: DataStoreManager,
    @ApplicationContext private val context: Context
) : classA {
    // 创建热流,replay=0表示只给新订阅者发送新事件
    private val _dialogDismissEvents = MutableSharedFlow<Unit>(replay = 0)
    override val dialogDismissEvents = _dialogDismissEvents.asSharedFlow()

    override fun getData() {}

    override fun openActivity() {
        val intent = Intent(context, ActivityA::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }

    override fun sendDialogDismissEvent() {
        // 在协程中发送事件
        CoroutineScope(Dispatchers.IO).launch {
            _dialogDismissEvents.emit(Unit)
        }
    }

    // 初始化时启动协程监听事件
    init {
        CoroutineScope(Dispatchers.IO).launch {
            dialogDismissEvents.collect {
                // 处理Dialog关闭事件
                handleDialogDismiss()
            }
        }
    }

    private fun handleDialogDismiss() {
        // classAImpl需要执行的逻辑
    }
}

2. 改造ActivityA

class ActivityA : AppCompatActivity, DialogListener {
    @Inject lateinit var classA: classA

    override fun onDialogDismiss() {
        // 发送事件给classAImpl
        classA.sendDialogDismissEvent()
        // 处理自身逻辑
    }
}

方案3:本地广播(不推荐,仅作备选)

通过LocalBroadcastManager实现事件传递,ActivityA发送广播,classAImpl注册接收器接收事件。但该方式耦合度高、效率低,已逐渐被响应式流替代。

代码实现

// 定义广播Action
const val ACTION_DIALOG_DISMISSED = "com.example.action.DIALOG_DISMISSED"

// classAImpl中注册广播接收器
@Singleton
class classAImpl @Inject constructor(
    private val dataStoreManager: DataStoreManager,
    @ApplicationContext private val context: Context
) : classA {
    private val broadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == ACTION_DIALOG_DISMISSED) {
                handleDialogDismiss()
            }
        }
    }

    init {
        LocalBroadcastManager.getInstance(context).registerReceiver(
            broadcastReceiver,
            IntentFilter(ACTION_DIALOG_DISMISSED)
        )
    }

    override fun getData() {}

    override fun openActivity() {
        val intent = Intent(context, ActivityA::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
    }

    private fun handleDialogDismiss() {
        // 处理逻辑
    }
}

// ActivityA中发送广播
class ActivityA : AppCompatActivity, DialogListener {
    override fun onDialogDismiss() {
        val intent = Intent(ACTION_DIALOG_DISMISSED)
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
        // 自身逻辑处理
    }
}

内容的提问来源于stack exchange,提问作者Saneen K P

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 11:05:03