很多时分我们需要维护一个大局可用的ViewModel,因为这样能够维护大局同一份数据源,且方便运用协程绑定App的生命周期。那如何设计大局可用的ViewModel对象?
一、思路
viewModel
对象是存储在ViewModelStore
中的,那么假如我们创立一个大局运用的ViewModelStore
而且在获取viewModel
对象的时分从它里边获取就能够了。
viewModel
是经过ViewModelProvider
的get
办法获取的,一般是ViewModelProvider(owner: ViewModelStoreOwner, factory: Factory).get(ViewModel::class.java)
。
如何将ViewModelProvider
与ViewModelStore
相关起来? 纽带就是ViewModelStoreOwner
, ViewModelStoreOwner
是一个接口,需要完成getViewModelStore()
办法,而该办法回来的就是ViewModelStore
:
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore(); //回来一个ViewModelStore
}
让某个类完成这个接口,重写办法回来我们界说的ViewModelStore
就能够了。
至于上面ViewModelProvider
结构办法的第二个参数Factory
是什么呢?
源码中供给了二种Factory
,一种是NewInstanceFactory
,一种是AndroidViewModelFactory
,它们的首要区别是:
-
NewInstanceFactory创立ViewModel时,会为每个Activity或Fragment创立一个新的ViewModel实例,这会导致ViewModel无法在应用程序的不同部分共享数据。(ComponentActivity源码getDefaultViewModelProviderFactory办法)
-
AndroidViewModelFactory能够拜访应用程序的大局状态,而且ViewModel实例能够在整个应用程序中是共享的。
依据我们的需求,需要用的是AndroidViewModelFactory。
二、具体完成
1、方式一:能够大局增加和获取恣意ViewModel
界说Application,Ktx.kt
文件
import android.app.Application
lateinit var appContext: Application
fun setApplicationContext(context: Application) {
appContext = context
}
界说大局可用的ViewModelOwner
完成类
object ApplicationScopeViewModelProvider : ViewModelStoreOwner {
private val eventViewModelStore: ViewModelStore = ViewModelStore()
override fun getViewModelStore(): ViewModelStore {
return eventViewModelStore
}
private val mApplicationProvider: ViewModelProvider by lazy {
ViewModelProvider(
ApplicationScopeViewModelProvider,
ViewModelProvider.AndroidViewModelFactory.getInstance(appContext)
)
}
fun <T : ViewModel> getApplicationScopeViewModel(modelClass: Class<T>): T {
return mApplicationProvider.get(modelClass)
}
}
界说一个ViewModel
经过StateFlow
界说发送和订阅事情的办法
class EventViewModel : ViewModel() {
private val mutableStateFlow = MutableStateFlow(0)
fun postEvent(state: Int) {
mutableStateFlow.value = state
}
fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = { _ -> }) {
val eventScope = scope ?: viewModelScope
eventScope.launch {
mutableStateFlow.collect {
method.invoke(it)
}
}
}
}
界说一个调用的类
object FlowEvent {
//发送事情
fun postEvent(state: Int) {
ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
.postEvent(state)
}
//订阅事情
fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = { _ -> }) {
ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
.observeEvent(scope, method)
}
}
测验代码如下:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//打印协程称号
System.setProperty("kotlinx.coroutines.debug", "on")
FlowEvent.observeEvent {
printMsg("MainActivity observeEvent before :$it")
}
//修正值
FlowEvent.postEvent(1)
FlowEvent.observeEvent {
printMsg("MainActivity observeEvent after :$it")
}
}
}
//日志
内容:MainActivity observeEvent before :0 线程:main @coroutine#1
内容:MainActivity observeEvent before :1 线程:main @coroutine#1
内容:MainActivity observeEvent after :1 线程:main @coroutine#2
2、方式二:更方便在Activity和Fragment中调用
界说Application,让BaseApplication
完成ViewModelStoreOwner
//BaseApplication完成ViewModelStoreOwner接口
class BaseApplication : Application(), ViewModelStoreOwner {
private lateinit var mAppViewModelStore: ViewModelStore
private var mFactory: ViewModelProvider.Factory? = null
override fun onCreate() {
super.onCreate()
//设置大局的上下文
setApplicationContext(this)
//创立ViewModelStore
mAppViewModelStore = ViewModelStore()
}
override fun getViewModelStore(): ViewModelStore = mAppViewModelStore
/**
* 获取一个大局的ViewModel
*/
fun getAppViewModelProvider(): ViewModelProvider {
return ViewModelProvider(this, this.getAppFactory())
}
private fun getAppFactory(): ViewModelProvider.Factory {
if (mFactory == null) {
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(this)
}
return mFactory as ViewModelProvider.Factory
}
}
Ktx.kt
文件也有改变,如下
lateinit var appContext: Application
fun setApplicationContext(context: Application) {
appContext = context
}
//界说扩展办法
inline fun <reified VM : ViewModel> Fragment.getAppViewModel(): VM {
(this.requireActivity().application as? BaseApplication).let {
if (it == null) {
throw NullPointerException("Application does not inherit from BaseApplication")
} else {
return it.getAppViewModelProvider().get(VM::class.java)
}
}
}
//界说扩展办法
inline fun <reified VM : ViewModel> AppCompatActivity.getAppViewModel(): VM {
(this.application as? BaseApplication).let {
if (it == null) {
throw NullPointerException("Application does not inherit from BaseApplication")
} else {
return it.getAppViewModelProvider().get(VM::class.java)
}
}
}
在BaseActivity
和BaseFragment
中调用上述扩展办法
abstract class BaseActivity: AppCompatActivity() {
//创立ViewModel对象
val eventViewModel: EventViewModel by lazy { getAppViewModel() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
abstract class BaseFragment: Fragment() {
//创立ViewModel对象
val eventViewModel: EventViewModel by lazy { getAppViewModel() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
测验代码
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//打印协程称号
System.setProperty("kotlinx.coroutines.debug", "on")
eventViewModel.observeEvent {
printMsg("MainActivity observeEvent :$it")
}
findViewById<AppCompatButton>(R.id.bt).setOnClickListener {
//点击按钮修正值
eventViewModel.postEvent(1)
//跳转到其他Activity
Intent(this, TwoActivity::class.java).also { startActivity(it) }
}
}
}
class TwoActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_two)
eventViewModel.observeEvent {
printMsg("TwoActivity observeEvent :$it")
}
}
}
日志
内容:MainActivity observeEvent :0 线程:main @coroutine#1
内容:MainActivity observeEvent :1 线程:main @coroutine#1
内容:TwoActivity observeEvent :1 线程:main @coroutine#2