很多时分我们需要维护一个大局可用的ViewModel,因为这样能够维护大局同一份数据源,且方便运用协程绑定App的生命周期。那如何设计大局可用的ViewModel对象?

一、思路

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

学习笔记