Android单Activity应用中NFC用例与Activity解耦方案咨询
单Activity架构下NFC用例与Activity解耦方案
你的中间类方案的问题
直接传入InBetweenClass和让NFC用例持有Activity引用本质上没有区别——中间类依然持有Activity的强引用,如果NFC用例的生命周期超过Activity(比如被全局单例持有),还是会导致Activity无法被GC回收,引发内存泄漏。这种包装只是增加了一层调用,并没有真正解耦。
推荐的解耦方案
方案一:ViewModel + LiveData(适配Jetpack单Activity架构)
利用ViewModel的生命周期特性(与Activity/Fragment绑定但不持有其引用),通过LiveData发送事件,让Activity自行处理NFC前台调度的启动与停止,NFC用例的逻辑完全封装在ViewModel中,无需直接接触Activity。
代码示例:
// NFC逻辑ViewModel class NfcViewModel : ViewModel() { private val _nfcAction = MutableLiveData<NfcAction>() val nfcAction: LiveData<NfcAction> = _nfcAction // 启动NFC前台调度 fun startForegroundDispatch() { _nfcAction.value = NfcAction.Start } // 停止NFC前台调度 fun stopForegroundDispatch() { _nfcAction.value = NfcAction.Stop } // 处理NFC扫描结果 fun handleNfcIntent(intent: Intent) { // 这里编写你的NFC标签解析、位置验证逻辑 // 扫描完成后自动停止调度 stopForegroundDispatch() } sealed class NfcAction { object Start : NfcAction() object Stop : NfcAction() } } // 单Activity实现 class MainActivity : AppCompatActivity() { private lateinit var nfcAdapter: NfcAdapter private val nfcViewModel by viewModels<NfcViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) nfcAdapter = NfcAdapter.getDefaultAdapter(this) ?: run { // 处理设备不支持NFC的情况 return } observeNfcActions() } private fun observeNfcActions() { nfcViewModel.nfcAction.observe(this) { action -> when (action) { NfcViewModel.NfcAction.Start -> enableNfcForegroundDispatch() NfcViewModel.NfcAction.Stop -> disableNfcForegroundDispatch() } } } private fun enableNfcForegroundDispatch() { val intent = Intent(this, javaClass).apply { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP } val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE) } else { PendingIntent.getActivity(this, 0, intent, 0) } nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null) } private fun disableNfcForegroundDispatch() { try { nfcAdapter.disableForegroundDispatch(this) } catch (e: Exception) { // 捕获异常,避免调度未启动时调用报错 } } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) intent?.takeIf { it.action == NfcAdapter.ACTION_TAG_DISCOVERED }?.let { nfcViewModel.handleNfcIntent(it) } } // 示例:在需要启动NFC扫描的地方调用 private fun startScan() { nfcViewModel.startForegroundDispatch() } }
方案二:接口抽象 + 弱引用
定义一个抽象调度接口,让Activity实现该接口,NFC用例持有接口的弱引用,既保证能调用调度方法,又不会因强引用导致Activity泄漏。
代码示例:
// 抽象NFC调度接口 interface NfcDispatcher { fun startForegroundDispatch() fun stopForegroundDispatch() } // NFC用例类 class NfcUseCase(private val dispatcherRef: WeakReference<NfcDispatcher>) { fun startScan() { dispatcherRef.get()?.startForegroundDispatch() } private fun stopScan() { dispatcherRef.get()?.stopForegroundDispatch() } fun handleNfcIntent(intent: Intent) { // 处理NFC扫描逻辑 // 扫描完成后自动停止 stopScan() } } // Activity实现接口 class MainActivity : AppCompatActivity(), NfcDispatcher { private lateinit var nfcAdapter: NfcAdapter private lateinit var nfcUseCase: NfcUseCase override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) nfcAdapter = NfcAdapter.getDefaultAdapter(this) ?: run { // 处理不支持NFC的情况 return } nfcUseCase = NfcUseCase(WeakReference(this)) } override fun startForegroundDispatch() { val intent = Intent(this, javaClass).apply { flags = Intent.FLAG_ACTIVITY_SINGLE_TOP } val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE) } else { PendingIntent.getActivity(this, 0, intent, 0) } nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null) } override fun stopForegroundDispatch() { try { nfcAdapter.disableForegroundDispatch(this) } catch (e: Exception) { // 处理异常 } } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) intent?.takeIf { it.action == NfcAdapter.ACTION_TAG_DISCOVERED }?.let { nfcUseCase.handleNfcIntent(it) } } }
方案对比
- ViewModel+LiveData:更贴合Jetpack生态,自动处理生命周期,无需手动管理弱引用,适合单Activity架构的现代Android应用。
- 接口+弱引用:更轻量化,不依赖Jetpack组件,适合传统架构或对依赖有严格限制的场景,但需要手动处理弱引用的空安全。
内容的提问来源于stack exchange,提问作者Emanuel
相关产品推荐
相关产品推荐

