Kotlin类与Activity双向通信:Dialog回调如何传递至classAImpl
Kotlin单例类与Activity双向通信解决方案
问题场景
在Android开发中,Activity与Fragment可通过ViewModel或接口实现通信,但对于**单例Kotlin类(如classAImpl)与Activity(如ActivityA)**的双向通信存在以下约束:
classAImpl是通过依赖注入初始化的单例,负责打开ActivityAActivityA实现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
相关产品推荐
相关产品推荐

