再MMVM架构中,activity持有ViewModel引用,ViewModel却不显示持有Activity的引用;这就导致ViewModel只能被动接受来自activity的数据(activity调用viewModel的方法传递数据)。
然而在某些场景下,viewModel需要主动去获取Activity中的数据。例如:
- viewModel的某个方法中需要Exoplayer的播放进度值进行逻辑判断。(viewModel不能直接持有Exoplayer/Activity的引用,所以不能主动查询)
- 同一Activity中有两个ViewMoel实例,AViewModel的某个方法中需要BViewModel的数据进行逻辑判断。(AViewModel不能直接持有BViewModel的引用,所以不能主动查询)
为了解决该问题,我们可以封装了一个简单的数据提供类(DataProvider)。
使用示例:
//Viewmodel中主动获取Activity数据示例
class AViewModel : ViewModel(){
val videoProgressDataProvider = DataProvider<Long>() //播放进度dataProvider
val vipStateDataProvider = DataProvider<Boolean>() //vip信息dataProvider
fun adLoadSuccess(){
val videoProgress = videoProgressDataProvider.getData()?:0 //实时获取当前播放进度
val isVip = vipStateDataProvider.getData()?:false //获取另一个Viewmodle中vip状态信息
if(videoProgress > 5 * 60 * 1000 && !isVip){
//show AD
}
}
}
//Activity向aviewModel提供数据
class DataProviderTestActivity: AppCompatActivity() {
private fun initViewModel(){
val aViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(AViewModel::class.java)
//向aViewModel提供播放进度
aViewModel.videoProgressDataProvider.provide(this){ //传入生命周期参数,页面销毁自动清除,防止内存泄漏
player.getCurrentPostion() //返回播放器的播放进度;运行在UI线程
}
//向aViewModel提供bViewModel的数据
aViewModel.vipStateDataProvider.provide(this){
bViewModel.isVIP() //返回vip状态
}
}
}
DataProvider源码:
class DataProvider<T>{
private var mProvider: Provider<T>? = null
private val mainHandler = Handler(Looper.getMainLooper())
fun provide(lifecycleOwner: LifecycleOwner, provider: Provider<T>){
this.mProvider = provider
lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver{
override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
lifecycleOwner.lifecycle.removeObserver(this)
mProvider = null
}
})
}
fun getData(): T?{
val isUiThread = Looper.myLooper() == Looper.getMainLooper() //保证mProvider?.onData()在主线程中执行
if(isUiThread){
return mProvider?.onData()
}else{
val latch = CountDownLatch(1)
var result: T? = null
mainHandler.post {
result = mProvider?.onData()
latch.countDown()
}
latch.await()
return result
}
}
}
注意事项:
1.DataProvider只能有一个最新的数据提供者有效,即provide()方法多次调用的话,最新的一次调用有效。
2.provider.onData()运行在UI线程,便于访问UI控件
完整项目地址:github.com/High-Power-…