如何替换Activity.runOnUiThread实现ViewModel无依赖UI线程操作?
问题:用Handler替换Activity.runOnUiThread实现ViewModel脱离Activity依赖是否正确?
我有一个接收Activity参数并在Activity UI线程运行的函数,该函数由ViewModel调用,希望将其修改为基于ViewModel实现且不依赖Activity。现将原代码中的activity.runOnUiThread替换为以下Handler实现,请问该写法是否正确?
原代码
@SuppressLint("MissingPermission") private fun onIntervalScanUpdate(over: Boolean, activity: Activity, bleStateCallback: BleStateCallback) { val devices: List<ScanResult> = ArrayList<ScanResult>(mDeviceMap.values) Collections.sort( devices ) { dev1: ScanResult, dev2: ScanResult -> val rssi1 = dev1.rssi val rssi2 = dev2.rssi rssi2.compareTo(rssi1) } activity.runOnUiThread(Runnable { mBleList.clear() mBleList.addAll(devices) if (over) { if(mBleList.isNotEmpty()) { Timber.d("xxx device found - ${mBleList.first().device.name}") mDevice = mBleList.first().device connect(bleStateCallback) } else { Timber.d("xxx device found - NONE") } } }) }
修改后的代码
val uiHandler = Handler(Looper.getMainLooper()) uiHandler.post { mBleList.clear() mBleList.addAll(devices) if (over) { if(mBleList.isNotEmpty()) { Timber.d("xxx device found - ${mBleList.first().device.name}") mDevice = mBleList.first().device connect(bleStateCallback) } else { Timber.d("xxx device found - NONE") } } }
回答
这个写法功能上是可行的:Handler(Looper.getMainLooper())确实能把任务投递到主线程执行,和activity.runOnUiThread的核心效果一致,而且不再依赖Activity实例,满足你让ViewModel脱离Activity的需求。
但有几个细节需要优化:
- 避免重复创建Handler:不要每次调用函数都新建
uiHandler实例,应该把它作为ViewModel的全局属性初始化一次,减少不必要的对象开销:private val uiHandler = Handler(Looper.getMainLooper()) - 防止内存泄漏:ViewModel的生命周期长于Activity,若Handler投递的任务在ViewModel销毁后仍未执行,可能引发泄漏。建议在ViewModel的
onCleared()方法中清理未完成的任务:override fun onCleared() { super.onCleared() uiHandler.removeCallbacksAndMessages(null) } - 推荐更贴合Jetpack的方案:其实用
ViewModel搭配Coroutines或LiveData是更标准的实现,无需手动管理线程切换,也更符合MVVM设计:- 用
viewModelScope(Coroutines)的示例:private fun onIntervalScanUpdate(over: Boolean, bleStateCallback: BleStateCallback) { val devices: List<ScanResult> = ArrayList(mDeviceMap.values) Collections.sort(devices) { dev1, dev2 -> dev2.rssi.compareTo(dev1.rssi) } viewModelScope.launch(Dispatchers.Main) { mBleList.clear() mBleList.addAll(devices) if (over) { if(mBleList.isNotEmpty()) { Timber.d("xxx device found - ${mBleList.first().device.name}") mDevice = mBleList.first().device connect(bleStateCallback) } else { Timber.d("xxx device found - NONE") } } } }viewModelScope会在ViewModel销毁时自动取消协程,从根源避免泄漏,代码也更简洁。
- 用
内容的提问来源于stack exchange,提问作者BRDroid
相关产品推荐
相关产品推荐

