区块链技术博客
www.b2bchain.cn

Android开发学习笔记——Jetpack之LiveData&ViewModel

这篇文章主要介绍了Android开发学习笔记——Jetpack之LiveData&ViewModel的讲解,通过具体代码实例进行20360 讲解,并且分析了Android开发学习笔记——Jetpack之LiveData&ViewModel的详细步骤与相关技巧,需要的朋友可以参考下https://www.b2bchain.cn/?p=20360

本文实例讲述了2、树莓派设置连接WiFi,开启VNC等等的讲解。分享给大家供大家参考文章查询地址https://www.b2bchain.cn/7039.html。具体如下:

Android开发学习笔记——Jetpack之LiveData&ViewModel

  • Jetpack
    • 概述
    • 基本使用
  • LiveData&ViewModel
    • LiveData
      • 基本使用
      • LiveData源码分析理解
    • ViewModel
      • 基本使用
      • ViewModel的生命周期
      • Fragment间共享数据
      • ViewModel和LiveData配合使用
  • 总结

Jetpack

概述

在Android的官方文档中,对Jetpack有如下描述:Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。
如谷歌官方所言,这个一个用于优化代码,提高开发效率的使用开发工具库的集合,对于我们的开发而言,我们可以不去使用Jetpack中推荐的库,但是,其中有一些工具确实能够有效提高我们的开发效率和代码质量,因此对于一些好用的库我们还是需要去学习下相关用法的,如ViewModel、Lifecycle、LiveData等。
Jetpack主要分为的组件主要分为4类:

  • 基础 – Foundation:提供了最基础的底层功能,如向后兼容性、测试、开发语言Kotlin支持等,如:AndroidKTX、AppCompat等
  • 架构 – Architecture:帮助开发者设计稳健、可测试且易维护的应用,如:DataBinding、Lifecycles、LiveData、Room、ViewModel、Nabagation和WorkManager等
  • 行为 – Behavior:帮助应用与标准的 Android 服务(如通知、权限、分享和 Google 助理)相集成,如CameraX、DownloadManager、Permissions和Preferences等
  • 界面 – UI:辅助绘制界面的View类 & 各种辅助组件,包括:Animation & Transitions、Emoji、Layout和Palette等
    Android开发学习笔记——Jetpack之LiveData&ViewModel

基本使用

对于Jetpack而言,Jetpack 库中所有的组件都可以单独使用,也可以组合使用,以满足应用的不同需求。所有 Jetpack 组件都可在 Google Maven 代码库中找到。在使用Jetpack之前,我们首先需要添加google代码库,打开项目的 build.gradle 文件并添加 google() 代码库,如下所示:

allprojects {     repositories {         google()         jcenter()     } } 

然后,我们就可以添加我们所需要的Jetpack组件的依赖即可使用了。

LiveData&ViewModel

LiveData和ViewModel属于两个比较轻量级且开发中最常用的两个Jetpack组件,这两个组件配合使用能够有效实现MVVM模式,有效降低代码耦合,提高代码质量。其中LiveData是一种具有生命周期的感知能力的可观察的数据存储器类,而ViewModel旨在以注重生命周期的方式存储和管理界面相关的数据。
首先,我们需要添加LiveData和ViewModel的依赖如下:

def lifecycle_version = "2.2.0" // ViewModel implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" // LiveData implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" 

LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
LiveData是一个基于观察者模式的数据存储类,这个描述说明了LiveData的本质特征,首先,LiveData是一个数据存储类,是用于存储数据的,同时他是基于观察者模式实现的,也就说我们能够通过观察者模式观察到LiveData对象的数据变化。不过和一般的观察者模式有所不同,LiveData还具有生命周期感知能力,LiveData 只会将更新通知给活跃的观察者,如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于Activity和Fragment而言,当其生命周期结束后,就会被移除,从而就可以避免内存泄漏。

基本使用

LiveData的基本使用很简单,基本可以分为以下几步:

  • 创建 LiveData 实例以存储某种类型的数据。这通常在 ViewModel 类中完成。
  • 创建可定义 onChanged() 方法的 Observer 对象,该方法可以控制当 LiveData 对象存储的数据更改时会发生什么。通常情况下,我们会在其中执行UI更新相关操作。
  • 调用LiveData对象的 observe() 方法建立观察者模式,将Observer对象添加到LiveData的观察者队列中,同时传入一个LifecycleOwner对象,LiveData将感知其生命周期,在其活跃状态时通知其更新。
  • 调用LiveData对象的setValue或者postValue方法更新其中的数据,其中setValue()方法只能在主线程发,而postValue()方法可以在子线程发。
    首先,我们创建一个LiveData对象。我们知道LiveData 实际上是一种可用于任何数据的封装容器,其中包括可实现 Collections 的对象,如 List。通常LiveData可以和ViewModel配合使用,在ViewModel中创建LiveData对象,这里,我们直接在Activity中创建一个LiveData对象,指定为String类型,通常我们会指定为Mutable可修改类型,如下:
private val text =  MutableLiveData<String>("default") 

然后,我们就可以创建Observer对象,并调用observe方法建立观察,observer方法有两个参数,第一个参数为一个LifeOwner对象,LiveData会监听其生命周期来决定是否发送通知,通常情况下,我们可以直接使用Activity和Fragment对象,因为其默认实现了LifeOwner接口,这样LiveData就会监听Activity和Fragment的生命周期,在其活跃的时候(onStart-onPause)发送其更新通知,在其销毁的时候移除观察者,从而避免了内存泄漏的风险;第二个参数就是一个Observer对象,通过实现其onChanged方法来执行LiveData数据发生改变时的逻辑,通常我们可以直接以lamda和匿名类的形式实现,如下:

text.observe(this) { value ->     //数据更新时,修改TextView的值     tvTest.text = value } 

最后,我们只需要调用setValue和postValue更新LiveData数据,Activity就能够观察到其数据变化进而更新TextView的值,如下:

btTest.setOnClickListener {     text.value = "click button" } 

Android开发学习笔记——Jetpack之LiveData&amp;ViewModel
点击按钮,TextView变为“click button”。

LiveData源码分析理解

我们可以看到,LiveData的基本使用非常简单,接下来,我们来简单分析其源码,来看看为什么LiveData能够感知生命周期?以及它是如何通知数据更新的?
我们知道,LiveData最重要的方法就是observe方法,首先,我们来看observe方法的源码:

@MainThread public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) { 	//断言,当前处于主线程     assertMainThread("observe");     //如果owner的生命周期结束,直接返回,忽略     if (owner.getLifecycle().getCurrentState() == DESTROYED) {         // ignore         return;     }     //生成一个绑定owner生命周期的observer对象     LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);     //将其放入LiveData的观察者队列中     ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);     //判断observer是否已存在     if (existing != null && !existing.isAttachedTo(owner)) {         throw new IllegalArgumentException("Cannot add the same observer"                 + " with different lifecycles");     }     if (existing != null) {         return;     }     //让observer能够感知到生命周期     owner.getLifecycle().addObserver(wrapper); } 

通过源码,首先我们能够知道observe方法只能在主线程中调用,否则无法通过断言,就会抛出异常。然后,我们看到,observe方法中,最后将我们传入的两个参数封装成了一个LifecycleBoundObserver对象,LifecycleBoundObserver类继承了ObserverWrapper类并且实现了LifecycleEventObserver接口,实现了onStateChanged方法,该方法能监听到LifecycleOwner的生命周期的变化。最后通过owner.getLifecycle().addObserver(wrapper)让observer能够感知到生命周期的变化,从而,我们通过onStateChanged方法就能监听到生命周期的变化了。如下所示:

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {     @NonNull     final LifecycleOwner mOwner;      LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {         super(observer);         mOwner = owner;     }      @Override     boolean shouldBeActive() {     	//在STARTED之后(onStart,onResume,onPause)才处于活跃状态,LiveData会通知数据更新         return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);     }      @Override     public void onStateChanged(@NonNull LifecycleOwner source,             @NonNull Lifecycle.Event event) { 		//当生命周期结束时移除observer         if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {             removeObserver(mObserver);             return;         }         //更新活跃状态,从非活跃状态变为活跃状态时会更新数据         activeStateChanged(shouldBeActive());     }      @Override     boolean isAttachedTo(LifecycleOwner owner) {         return mOwner == owner;     }      @Override     void detachObserver() {         mOwner.getLifecycle().removeObserver(this);     } } 

我们发现,在onStateChanged中,如果当前生命周期已经结束就会移除observer,从而也就避免了内存泄漏的问题。那么,数据更新后,LiveData又是如何发送通知的呢?我们知道,修改数据是通过setValue和postValue来进行的,我们首先看setValue方法,如下:

@MainThread protected void setValue(T value) { 	//断言,主线程中执行     assertMainThread("setValue");     //更新版本和数据     mVersion++;     mData = value;     //分发数据     dispatchingValue(null); } 

首先,我们可以看到,在setValue中,我们也必须在主线程中执行,否则就会报错。跟着代码,我们继续查看dispatchingValue方法,如下:

void dispatchingValue(@Nullable ObserverWrapper initiator) {     if (mDispatchingValue) {         mDispatchInvalidated = true;         return;     }     mDispatchingValue = true;     do {         mDispatchInvalidated = false;         if (initiator != null) {             considerNotify(initiator);             initiator = null;         } else {         //核心代码,遍历LiveData的所有observer             for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =                     mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {                 considerNotify(iterator.next().getValue());                 if (mDispatchInvalidated) {                     break;                 }             }         }     } while (mDispatchInvalidated);     mDispatchingValue = false; } 

dispatchingValue中的核心代码在于遍历了LiveData的所有observer,并调用了considerNotify方法,如下:

private void considerNotify(ObserverWrapper observer) { 	//如果处于非活跃状态,直接返回,不做处理     if (!observer.mActive) {         return;     }     // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.     //     // we still first check observer.active to keep it as the entrance for events. So even if     // the observer moved to an active state, if we've not received that event, we better not     // notify for a more predictable notification order.     if (!observer.shouldBeActive()) {         observer.activeStateChanged(false);         return;     }     //判断当前版本是否落后,需要更新状态     if (observer.mLastVersion >= mVersion) {         return;     }     observer.mLastVersion = mVersion;     //调用onChanged通知数据变化     observer.mObserver.onChanged((T) mData); } 

considerNotify方法中会通过shouldBeActive方法判断当前是否处于活跃状态,如果处于非活跃状态则直接返回,不通知数据更新,否则就会调用observer对象的onChanged方法,通知数据变化,至此也就完成了LiveData的数据更新变化和通知过程。
而postValue和setValue实际上实现差不多,不同的时,postValue是通过Handler机制将消息发送到主线程中,因此能够在子线程中使用,但最后实际上还是调用了setValue。

ViewModel

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
提到ViewModel,我们就会想到MVVM模式,在MVVM模式中,是由数据驱动视图,即当界面上的数据发生变化时,视图自动更新,而不是每次改变数据都去手动更新视图,实际上就是一个观察者模式。MVVM模式中,数据和视图完全分离,而ViewModel以及LiveData的出现为MVVM模式提供了很多方便。

基本使用

ViewModel的基本使用非常简单,因为其本质就相当于一个实体类,其作用就是维护视图层的数据状态,我们所需要做的就是继承ViewModel,然后再其中保存对应的数据状态,然后在视图层使用即可。比如存在一个登录界面,需要输入账号和密码,其ViewModel如下:

class LoginViewModel : ViewModel() {     val userName : String = ""     val password : String = "" } 

然后,我们只需要在视图层即Activity和Fragment中使用即可,如下:

loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) loginViewModel.userName loginViewModel.password 

我们可以看到ViewModel的使用简单的不可思议,那么这和我们一般直接创建一个实体类好像没有什么区别,唯一区别就是继承了ViewModel,那么我们为什么还要使用ViewModel呢?ViewModel主要提供了两个便利,如下:

  • 关联生命周期,配置更改期间自动保留其数据 (比如屏幕的横竖旋转)
  • Activity、Fragment等UI组件之间的通信

ViewModel的生命周期

我们知道,由系统响应用户交互或者重建组件,用户无法操控。当组件被销毁并重建后,原来组件相关的数据也会丢失——最简单的例子就是屏幕的旋转,如果数据类型比较简单,同时数据量也不大,可以通过onSaveInstanceState()存储数据,组件重建之后通过onCreate(),从中读取Bundle恢复数据。但如果是大量数据,不方便序列化及反序列化,则上述方法将不适用。
ViewModel则会在这种情况下自动保留其数据,如果重新创建了该 Activity,它接收的 MyViewModel 实例与第一个 Activity 创建的实例相同。直到当所有的 Activity 都finish时,才调用 ViewModel 对象的 onCleared() 方法,以便它可以清理资源。
ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProvider 的 Lifecycle。ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失:对于 Activity,是在 Activity 完成时;而对于 Fragment,是在 Fragment 分离时。如下图:
Android开发学习笔记——Jetpack之LiveData&amp;ViewModel
我们可以写一个简单的计数器的例子,如下:

private var num = 0 override fun onCreate(savedInstanceState: Bundle?) {     super.onCreate(savedInstanceState)     setContentView(R.layout.activity_view_model)     tvTest.text = num.toString()     btTest.setOnClickListener {         num += 1         tvTest.text = num.toString()     } } 

我们多次点击按钮,数字变化,此时如果我们屏幕反转变为横屏,我们知道,此时Activity会被销毁重建,如果我们没有在onSaveInstanceState中保存数据状态,此时,数据就会被清空变为0,而ViewModel则不需要我们去手动保存数据状态。如下:

private lateinit var testViewModel : TestViewModel  override fun onCreate(savedInstanceState: Bundle?) {     super.onCreate(savedInstanceState)     setContentView(R.layout.activity_view_model)      //获取viewModel实例     testViewModel = ViewModelProvider(this).get(TestViewModel::class.java)     tvTest.text = testViewModel.num.toString()      btTest.setOnClickListener {         testViewModel.num += 1         tvTest.text = testViewModel.num.toString()     } } 

此时,如果我们翻转屏幕,数字不会被重置为0,这在界面如果拥有大量复杂数据时,这对于我们能够提供极大的便利。

Fragment间共享数据

当我们在开发中Activity中存在多个Fragment,而且其中不同的Fragment还需要使用到同一个数据时,这时Fragment和Activity之间的通信是不可避免的,此时如果我们使用ViewModel,只要ViewModelProvider传入的是同一个Activity对象,那么ViewModelProvider就会提供同一个ViewModel实例,那么也就实现了Fragment间的数据共享,而不需要通过Activity来实现Fragment间的通信,这会减少我们的开发成本,如下:

class AFragment : Fragment() {      private lateinit var testViewModel : TestViewModel     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         testViewModel = ViewModelProvider(requireActivity()).get(TestViewModel::class.java)     } }  class BFragment : Fragment() {      private lateinit var testViewModel : TestViewModel     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         testViewModel = ViewModelProvider(requireActivity()).get(TestViewModel::class.java)     } }  

请注意,这两个 Fragment 都会检索包含它们的 Activity。这样,当这两个 Fragment 各自获取 ViewModelProvider 时,它们会收到相同的 TestViewModel实例(其范围限定为该 Activity)。使用这种方法,Activity将不需要执行任何操作,而Fragment之间也不需要有任何接触,完全独立,互不干扰。

ViewModel和LiveData配合使用

在实际开发中,我们通常可以将ViewModel和LiveData配合使用,实现MVVM模式,将视图层和数据完全分离,我们可以在ViewModel中持有LiveData来维护保存数据的状态,在视图层观察LiveData的对象从而自动更新视图。如上述的计数器例子,我们可以做如下修改:

private lateinit var testViewModel : TestViewModel  override fun onCreate(savedInstanceState: Bundle?) {     super.onCreate(savedInstanceState)     setContentView(R.layout.activity_view_model)      //获取viewModel实例     testViewModel = ViewModelProvider(this).get(TestViewModel::class.java)     //观察数据变化     testViewModel.num.observe(this) {         tvTest.text = it.toString()     }     //更新数据     btTest.setOnClickListener {         testViewModel.num.value = testViewModel.num.value?.plus(1)     } } 

至此,ViewModel的基本使用就完成了。

总结

LiveData和ViewModel的基本使用相对比较简单,但是要想在项目中灵活运用,需要对其有足够的理解,还需要多看看LiveData和ViewModel的相关实例代码,看看其在实际的项目中的使用,多学习下。

本文转自互联网,侵权联系删除Android开发学习笔记——Jetpack之LiveData&ViewModel

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » Android开发学习笔记——Jetpack之LiveData&ViewModel
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们