详解Android如何设计一个全局可调用的ViewModel对象

Roselani ·
更新时间:2024-09-20
· 553 次阅读

目录

一、思路

二、具体实现

1、方式一:可以全局添加和获取任意ViewModel

2、方式二:更方便在Activity和Fragment中调用

一、思路

viewModel对象是存储在ViewModelStore中的,那么如果我们创建一个全局使用的ViewModelStore并且在获取viewModel对象的时候从它里面获取就可以了。

viewModel是通过ViewModelProviderget方法获取的,一般是ViewModelProvider(owner: ViewModelStoreOwner, factory: Factory).get(ViewModel::class.java)

如何将ViewModelProviderViewModelStore关联起来? 纽带就是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) } } }

BaseActivityBaseFragment中调用上述扩展方法

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

以上就是详解Android如何设计一个全局可调用的ViewModel对象的详细内容,更多关于Android ViewModel对象的资料请关注软件开发网其它相关文章!



调用 Android

需要 登录 后方可回复, 如果你还没有账号请 注册新账号