设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间23 现在时间23 缓存数据 好好的睡一觉吧,闭上眼睛做个好梦,明天睁眼又会是美好的一天,晚安好梦。

好好的睡一觉吧,闭上眼睛做个好梦,明天睁眼又会是美好的一天,晚安好梦。

查看: 1263|回复: 2

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

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:205
  • 打卡月天数:0
  • 打卡总奖励:3314
  • 最近打卡:2023-08-27 04:20:45
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
371
主题
348
精华
0
金钱
4428
积分
746
注册时间
2022-12-24
最后登录
2025-3-13

发表于 2023-7-21 00:50:10 | 显示全部楼层 |阅读模式
一、思路
  1. viewModel
复制代码
对象是存储在
  1. ViewModelStore
复制代码
中的,那么如果我们创建一个全局使用的
  1. ViewModelStore
复制代码
并且在获取
  1. viewModel
复制代码
对象的时候从它里面获取就可以了。
  1. viewModel
复制代码
是通过
  1. ViewModelProvider
复制代码
  1. get
复制代码
方法获取的,一般是
  1. ViewModelProvider(owner: ViewModelStoreOwner, factory: Factory).get(ViewModel::class.java)
复制代码

如何将
  1. ViewModelProvider
复制代码
  1. ViewModelStore
复制代码
关联起来? 纽带就是
  1. ViewModelStoreOwner
复制代码
,
  1. ViewModelStoreOwner
复制代码
是一个接口,需要实现
  1. getViewModelStore()
复制代码
方法,而该方法返回的就是
  1. ViewModelStore
复制代码
:
  1. public interface ViewModelStoreOwner {
  2.     /**
  3.      * Returns owned {@link ViewModelStore}
  4.      *
  5.      * @return a {@code ViewModelStore}
  6.      */
  7.     @NonNull
  8.     ViewModelStore getViewModelStore();   //返回一个ViewModelStore
  9. }
复制代码
让某个类实现这个接口,重写方法返回我们定义的
  1. ViewModelStore
复制代码
就可以了。
至于上面
  1. ViewModelProvider
复制代码
构造方法的第二个参数
  1. Factory
复制代码
是什么呢?
源码中提供了二种
  1. Factory
复制代码
,一种是
  1. NewInstanceFactory
复制代码
,一种是
  1. AndroidViewModelFactory
复制代码
,它们的主要区别是:

  • NewInstanceFactory创建ViewModel时,会为每个Activity或Fragment创建一个新的ViewModel实例,这会导致ViewModel无法在应用程序的不同部分共享数据。(ComponentActivity源码getDefaultViewModelProviderFactory方法)
  • AndroidViewModelFactory可以访问应用程序的全局状态,并且ViewModel实例可以在整个应用程序中是共享的。
根据我们的需求,需要用的是AndroidViewModelFactory。

二、具体实现


1、方式一:可以全局添加和获取任意
  1. ViewModel
复制代码


定义Application,
  1. Ktx.kt
复制代码
文件
  1. import android.app.Application

  2. lateinit var appContext: Application

  3. fun setApplicationContext(context: Application) {
  4.     appContext = context
  5. }
复制代码
定义全局可用的
  1. ViewModelOwner
复制代码
实现类
  1. object ApplicationScopeViewModelProvider : ViewModelStoreOwner {

  2.     private val eventViewModelStore: ViewModelStore = ViewModelStore()

  3.     override fun getViewModelStore(): ViewModelStore {
  4.         return eventViewModelStore
  5.     }

  6.     private val mApplicationProvider: ViewModelProvider by lazy {
  7.         ViewModelProvider(
  8.             ApplicationScopeViewModelProvider,
  9.             ViewModelProvider.AndroidViewModelFactory.getInstance(appContext)
  10.         )
  11.     }

  12.     fun <T : ViewModel> getApplicationScopeViewModel(modelClass: Class<T>): T {
  13.         return mApplicationProvider.get(modelClass)
  14.     }
  15. }
复制代码
定义一个
  1. ViewModel
复制代码
通过
  1. StateFlow
复制代码
定义发送和订阅事件的方法
  1. class EventViewModel : ViewModel() {

  2.     private val mutableStateFlow = MutableStateFlow(0)

  3.     fun postEvent(state: Int) {
  4.         mutableStateFlow.value = state
  5.     }

  6.     fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = { _ -> }) {
  7.         val eventScope = scope ?: viewModelScope
  8.         eventScope.launch {
  9.             mutableStateFlow.collect {
  10.                 method.invoke(it)
  11.             }
  12.         }
  13.     }
  14. }
复制代码
定义一个调用的类
  1. object FlowEvent {

  2.     //发送事件
  3.     fun postEvent(state: Int) {
  4.         ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
  5.             .postEvent(state)
  6.     }

  7.     //订阅事件
  8.     fun observeEvent(scope: CoroutineScope? = null, method: (Int) -> Unit = { _ -> }) {
  9.         ApplicationScopeViewModelProvider.getApplicationScopeViewModel(EventViewModel::class.java)
  10.             .observeEvent(scope, method)
  11.     }
  12. }
复制代码
测试代码如下:
  1. class MainActivity : AppCompatActivity() {

  2.     override fun onCreate(savedInstanceState: Bundle?) {
  3.         super.onCreate(savedInstanceState)
  4.         setContentView(R.layout.activity_main)
  5.         //打印协程名称
  6.         System.setProperty("kotlinx.coroutines.debug", "on")

  7.         FlowEvent.observeEvent {
  8.             printMsg("MainActivity observeEvent before :$it")
  9.         }
  10.         //修改值
  11.         FlowEvent.postEvent(1)


  12.         FlowEvent.observeEvent {
  13.             printMsg("MainActivity observeEvent after :$it")
  14.         }

  15.     }

  16. }

  17. //日志
  18. 内容:MainActivity observeEvent before :0 线程:main @coroutine#1
  19. 内容:MainActivity observeEvent before :1 线程:main @coroutine#1
  20. 内容:MainActivity observeEvent after :1 线程:main @coroutine#2
复制代码
2、方式二:更方便在Activity和Fragment中调用

定义Application,让
  1. BaseApplication
复制代码
实现
  1. ViewModelStoreOwner
复制代码
  1. //BaseApplication实现ViewModelStoreOwner接口
  2. class BaseApplication : Application(), ViewModelStoreOwner {

  3.     private lateinit var mAppViewModelStore: ViewModelStore
  4.     private var mFactory: ViewModelProvider.Factory? = null

  5.     override fun onCreate() {
  6.         super.onCreate()
  7.         //设置全局的上下文
  8.         setApplicationContext(this)
  9.         //创建ViewModelStore
  10.         mAppViewModelStore = ViewModelStore()

  11.     }

  12.     override fun getViewModelStore(): ViewModelStore = mAppViewModelStore

  13.     /**
  14.      * 获取一个全局的ViewModel
  15.      */
  16.     fun getAppViewModelProvider(): ViewModelProvider {
  17.         return ViewModelProvider(this, this.getAppFactory())
  18.     }

  19.     private fun getAppFactory(): ViewModelProvider.Factory {
  20.         if (mFactory == null) {
  21.             mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(this)
  22.         }
  23.         return mFactory as ViewModelProvider.Factory
  24.     }
  25. }
复制代码
  1. Ktx.kt
复制代码
文件也有变化,如下
  1. lateinit var appContext: Application

  2. fun setApplicationContext(context: Application) {
  3.     appContext = context
  4. }

  5. //定义扩展方法
  6. inline fun <reified VM : ViewModel> Fragment.getAppViewModel(): VM {
  7.     (this.requireActivity().application as? BaseApplication).let {
  8.         if (it == null) {
  9.             throw NullPointerException("Application does not inherit from BaseApplication")
  10.         } else {
  11.             return it.getAppViewModelProvider().get(VM::class.java)
  12.         }
  13.     }
  14. }

  15. //定义扩展方法
  16. inline fun <reified VM : ViewModel> AppCompatActivity.getAppViewModel(): VM {
  17.     (this.application as? BaseApplication).let {
  18.         if (it == null) {
  19.             throw NullPointerException("Application does not inherit from BaseApplication")
  20.         } else {
  21.             return it.getAppViewModelProvider().get(VM::class.java)
  22.         }
  23.     }
  24. }
复制代码
  1. BaseActivity
复制代码
  1. BaseFragment
复制代码
中调用上述扩展方法
  1. abstract class BaseActivity: AppCompatActivity() {

  2.     //创建ViewModel对象
  3.     val eventViewModel: EventViewModel by lazy { getAppViewModel() }

  4.     override fun onCreate(savedInstanceState: Bundle?) {
  5.         super.onCreate(savedInstanceState)

  6.     }
  7. }
复制代码
  1. abstract class BaseFragment: Fragment() {

  2.     //创建ViewModel对象
  3.     val eventViewModel: EventViewModel by lazy { getAppViewModel() }

  4.     override fun onCreate(savedInstanceState: Bundle?) {
  5.         super.onCreate(savedInstanceState)

  6.     }
  7. }
复制代码
测试代码
  1. class MainActivity : BaseActivity() {

  2.     override fun onCreate(savedInstanceState: Bundle?) {
  3.         super.onCreate(savedInstanceState)
  4.         setContentView(R.layout.activity_main)
  5.         //打印协程名称
  6.         System.setProperty("kotlinx.coroutines.debug", "on")

  7.         eventViewModel.observeEvent {
  8.             printMsg("MainActivity observeEvent :$it")
  9.         }

  10.         findViewById<AppCompatButton>(R.id.bt).setOnClickListener {
  11.             //点击按钮修改值
  12.             eventViewModel.postEvent(1)
  13.             //跳转到其他Activity
  14.             Intent(this, TwoActivity::class.java).also { startActivity(it) }
  15.         }
  16.     }

  17. }
复制代码
  1. class TwoActivity : BaseActivity() {

  2.     override fun onCreate(savedInstanceState: Bundle?) {
  3.         super.onCreate(savedInstanceState)
  4.         setContentView(R.layout.activity_two)

  5.         eventViewModel.observeEvent {
  6.             printMsg("TwoActivity observeEvent :$it")
  7.         }
  8.     }
  9. }
复制代码
日志
  1. 内容:MainActivity observeEvent :0 线程:main @coroutine#1
  2. 内容:MainActivity observeEvent :1 线程:main @coroutine#1
  3. 内容:TwoActivity observeEvent :1 线程:main @coroutine#2
复制代码
以上就是详解Android如何设计一个全局可调用的ViewModel对象的详细内容,更多关于Android ViewModel对象的资料请关注晓枫资讯其它相关文章!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
18
积分
16
注册时间
2022-12-28
最后登录
2022-12-28

发表于 2023-7-26 21:44:57 | 显示全部楼层
感谢分享~~~~学习学习~~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
22
积分
24
注册时间
2022-12-29
最后登录
2022-12-29

发表于 2023-7-27 05:11:01 | 显示全部楼层
感谢大大分享~~~~~~~~
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表