我是靠谱客的博主 灵巧薯片,这篇文章主要介绍Android ViewModel详解ViewModel简介ViewModel生命周期ViewModel 使用ktx 扩展AndroidViewModelViewModel onCleared 原理解析,现在分享给大家,希望可以做个参考。

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119828016
本文出自【赵彦军的博客】

文章目录

  • ViewModel简介
  • ViewModel生命周期
  • ViewModel 使用
    • Fragment使用
  • ktx 扩展
    • activity 扩展
    • fragment 扩展
  • AndroidViewModel
  • ViewModel onCleared 原理解析
    • Activity 中的 ViewModel 原理
    • Fragment 中的 ViewModel 原理
      • 因为 Activity 销毁导致 Fragment 销毁
      • 因为 Fragment 替换导致 Fragment 销毁

ViewModel简介

视图与数据模型之间的桥梁ViewModel

ViewModel生命周期

在这里插入图片描述
ViewModel的生命周期会比创建它的Activity、Fragment的生命周期都要长。即ViewModel中的数据会一直存活在Activity/Fragment中。

众所周知,由于Android平台的特殊性,若应用程序发送屏幕旋转的时候会经历Activity的销毁与重建,这里就涉及到数据保存的问题。虽然Activity可以通过onSaveInstanceState()机制保存与恢复数据,但是onSaveInstanceState()方法只能存储少量的数据进行恢复,但是遇到大量的数据该怎么办呢?

幸运的是,ViewModel能完美的为我们解决这个问题,ViewModel有自己独立的生命周期,屏幕旋转所导致的Activity重建,并不会影响ViewModel的生命周期.

ViewModel 使用

复制代码
1
2
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'

写一个继承自ViewModel的类

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MyViewModel : ViewModel() { private val users: MutableLiveData<List<User>> by lazy { MutableLiveData<List<User>>().also { loadUsers() } } fun getUsers(): LiveData<List<User>> { return users } private fun loadUsers() { // Do an asynchronous operation to fetch users. } }

使用:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val mainViewModel = ViewModelProvider(this).get(MyViewModel::class.java) mainViewModel.getUsers() //或者引入 extensions //implementation "android.arch.lifecycle:extensions:1.1.1" val mainViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java); } }

ViewModel是一个抽象类,其中只有一个onCleared()方法。当ViewModel不再被需要,即与之相关的Activity都被销毁时,该方法会被系统调用。我们可以在该方法中执行一些资源释放的相关操作。注意: 当屏幕旋转而导致的Activity重建,并不会调用该方法。

复制代码
1
2
3
4
5
6
7
8
class MyViewModel : ViewModel() { override fun onCleared() { super.onCleared() //viewModel销毁时调用,可以做一些释放资源的操作 } }

我们可以在onCleared()对定时器资源的释放,防止造成内存泄露。

Fragment使用

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class ItemFragment : Fragment() { var mainViewModel: MyViewModel? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val mainViewModel = ViewModelProvider(requireActivity()).get(MyViewModel::class.java) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_item_list, container, false) return view } }

ktx 扩展

activity 扩展

在上面我们介绍了,在activity里获取 viewModel 实例的方法,如下:

复制代码
1
2
val mainViewModel = ViewModelProvider(this).get(MyViewModel::class.java)

但是 Kotlin 的 ktx 扩展包里面有更为简洁的方式,添加依赖如下:

复制代码
1
2
implementation "androidx.activity:activity-ktx:1.3.1"

使用如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
class MainActivity : AppCompatActivity() { val mainViewModel by viewModels<MyViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) mainViewModel.name = "hhhh" } }

viewModels 扩展方法如下:

复制代码
1
2
3
4
5
6
7
8
9
10
public inline fun <reified VM : ViewModel> ComponentActivity.viewModels( noinline factoryProducer: (() -> Factory)? = null ): Lazy<VM> { val factoryPromise = factoryProducer ?: { defaultViewModelProviderFactory } return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise) }

fragment 扩展

对于 fragment 我们以前是使用:

复制代码
1
2
val mainViewModel = ViewModelProvider(requireActivity()).get(MyViewModel::class.java)

同理,我们添加 fragment ktx 扩展

复制代码
1
2
implementation "androidx.fragment:fragment-ktx:1.3.6"

就可以使用 :

复制代码
1
2
val mainViewModel: MyViewModel by activityViewModels()

具体代码如下

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ItemFragment : Fragment() { val mainViewModel: MyViewModel by activityViewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_item_list, container, false) return view } }

AndroidViewModel

使用ViewModel的时候,需要注意的是ViewModel不能够持有View、Lifecycle、Acitivity引用,而且不能够包含任何包含前面内容的类。因为这样很有可能会造成内存泄漏。

普通的 ViewModel 生命周期都很短,随着activity 销毁而销毁。如果我们要创建一个长生命周期的 ViewModel 怎么办? 其实Android 已经给我们提供了一个 AndroidViewModel

下面是一个AndroidViewModel的源码:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class AndroidViewModel extends ViewModel { @SuppressLint("StaticFieldLeak") private Application mApplication; public AndroidViewModel(@NonNull Application application) { mApplication = application; } /** * Return the application. */ @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"}) @NonNull public <T extends Application> T getApplication() { return (T) mApplication; } }

可以看到 AndroidViewModel 持有了一个 Application ,所以它的生命周期会很长。

具体使用如下:

复制代码
1
2
3
4
5
6
7
8
9
class MyViewModel(application: Application) : AndroidViewModel(application) { override fun onCleared() { super.onCleared() //viewModel销毁时调用,可以做一些释放资源的操作 } }

其实延伸开,我们完全可以在 AndroidViewModel 中存储一些全局数据。

ViewModel onCleared 原理解析

你有没有想过,当 ActivityFragment 销毁的时候,ViewModelonCleared 方法为什么会回调?

当你看到下面这两个图,你就明白了

Activity 中的 ViewModel 原理

ComponentActivity 注册 LifecycleEventObserver , 在 onDestory() 执行 getViewModelStore().clear();
在这里插入图片描述
ViewModelStore
在这里插入图片描述
上面就是 Activity 的原理。

Fragment 中的 ViewModel 原理

因为 Activity 销毁导致 Fragment 销毁

对于 Fragment 来说,要复杂一下:

FragmentActivity

在这里插入图片描述
FragmentController

在这里插入图片描述

FragmentStateManager

在这里插入图片描述

FragmentManagerViewModel

在这里插入图片描述

因为 Fragment 替换导致 Fragment 销毁

比如在 Activity 先执行 , add 方法

复制代码
1
2
3
4
supportFragmentManager.beginTransaction() .add(R.id.fragc, MyFragmentA(), "sdsds") .commitAllowingStateLoss()

再执行 replace 方法

复制代码
1
2
3
4
supportFragmentManager.beginTransaction() .replace(R.id.fragc, MyFragmentB(), "sdsds") .commitAllowingStateLoss()

执行完 replace MyFragmentB , 那么 MyFragmentA 就会被销毁。对应的 MyFragmentA 中的 ViewModel 就会执行 onCleared 方法。

原理如下:

FragmentStateManager

在这里插入图片描述

FragmentManagerViewModel

在这里插入图片描述

这种情况和上一种不一样 。

本次情况 Activity 没销毁,是因为 fragment 执行 replace 导致前 fragment 销毁。
而上一种情况是因为 Activity 销毁,导致 fragment 销毁。

最后

以上就是灵巧薯片最近收集整理的关于Android ViewModel详解ViewModel简介ViewModel生命周期ViewModel 使用ktx 扩展AndroidViewModelViewModel onCleared 原理解析的全部内容,更多相关Android内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部