Jetpack学习---Mvvm

子车俊材
2023-12-01


Jetpack

Jetpack 是一个由多个库组成的套件,可帮助开发者遵循最佳做法,减少样板代码并编写可在各种 Android 版本和设备中一致运行的代码,让开发者精力集中编写重要的代码。

架构组件

Android 架构组件是一组库,可帮助您设计稳健、可测试且易维护的应用。您可以从管理界面组件生命周期和处理数据持久性的类着手。

通过应用架构指南,学习有关汇编稳健应用的基础知识。
管理应用的生命周期。新的生命周期感知型组件可帮助您管理 Activity 和 Fragment 的生命周期。在配置更改后继续有效、避免内存泄漏,以及将数据轻松加载到界面中。
使用 LiveData 构建数据对象,在基础数据库改变时通知视图。
ViewModel 存储界面相关的数据,这些数据不会在应用旋转时销毁。
Room 是一个 SQLite 对象映射库。它可用来避免样板代码,还可以轻松地将 SQLite 表数据转换为 Java 对象。Room 提供 SQLite 语句的编译时检查,并且可以返回 RxJava、Flowable 和 LiveData 可观察对象。

MVC框架

model,view,controller
view持有controller,controller通过接口回调通知view
controller持有model,model通过接口回调通知controller数据更新
model通过接口回调通知view的UI更新

缺点:代码量过量冗余,全部在view层

优点:将代码分离开,有助于代码的查看和阅读

MVP框架

model,view,presenter
view持有controller,presenter通过接口回调通知view的UI更新
presenter持有model,model通过接口回调通知presenter数据更新

缺点:接口过多,多个view持有同一个presenter层时,会有很多无用的接口
问题:view的生命周期
问题:是否在主线程

优点:代码量分离开,减少view的代码冗余
将代码分离开,有助于代码的查看和阅读

MVVM框架

View ,ViewModel,Repository(Model和Remote Data Source)

View:Activity/Fragment 持有ViewModel层(通过观察者模式对LiveData对象进行监听)
ViewModel:类似于Presenter层(持有LiveData对象) 持有Repository层
Repository:Model(SQLite)和RomoteDataSource(网络资源)

由MVP到MVVM的演变

UI驱动 转变为数据驱动开发

UI驱动:根据是否修改UI来开发
数据驱动:根据数据修改来推动开发

mvp中多个view持有同一个presenter层时,会有很多无用的接口。
例如:一个音乐器播放器程序有播放器的presenter层(逻辑层),多个页面都会有播放器的效果,所以多个页面持有该逻辑层,但是由于功能不一样,但是持有该presenter层,导致有好多无效的回调接口。
解决该问题:数据驱动开发(关注数据:当前播放歌曲和当前播放状态) 对数据进行监听,如果歌曲变化的时候(可以监听数据变化的容器DataListenerContainer)
数据容器(Container):添加数据监听方法,删除数据监听方法。添加数据T的方法(多个数据用集合来保存)。
通过添加数据监听方法:通过不同的数据改变,来改变UI变化。(在需要改变UI的地方改变监听数据)

问题:是否在主线程
在 添加数据监听时,判断是否时主线程(系统代码),如果时主线程,直接添加数据。不是主线程,通过application的handler 来post到主线程中。

问题:view的生命周期
View通知Presenter的生命周期方法(presenter.onCreate)
在Presenter定义实现可以感知生命周期的接口类(ILifeCycler)然后再View层中实现所有的方法。(过多接口通过BaseActivity来)
在BaseActivity中 复写所有的方法。由于ILifeCycler来感知生命周期变化,只有每个Activity中现实了该接口就可以感知生命周期的变化。在BaseActivity中通过一个集合来保存lifecycler类来添加不同Presenter中的生命周期感知。
所以,要添加监听方法 ,和删除监听方法。

LifecycleProvider来管理生命周期的管理:保存当前View的生命周期
Fragment中也要Presenter类
添加监听,删除监听,管理生命周期状态枚举类方法(根据状态来通知生命周期变化)。
在BaseActivity和Fragment中创建Provider类。在不同生命周期中改变状态

让View的生命周期变化注册交给Presenter层
presenter层不实现ILifeCycler则不能添加生命周期方法监听
可以将provider给到Presenter层通过一个LifeCyclerOwner来获取Provider(通过baseActivity来现实Owner返回当前provider)
在presenter传入的provider添加当前的生命周期监听方法

数据容器监听View的生命周期变化(在用户可见的生命周期更新)
在数据监听的时候传入owner 获取provider对象(有可能有多个View进行监听,所有有多个owner)用集合来管理起来hashmap来保存(key:数据类型,value:provider)
在传入数据的判断当前的view的生命周期状态 通过isAtLeast(至少要START才更新)compareTo方法。(按顺序来比较。)

valueObserverWrapper用来管理value的(provider)的生命周期变化
如果时destory的时候,将provider删除掉,不再监听

DataContainer() 数据容器。(LiveData)一般在逻辑层
添加数据监听方法(用于数据变化时,监听数据从而改变UI变化一般在View中监听)更加数据setvalue方法用于更改数据然后通知数据监听(在逻辑层,什么时候需要更改数据)

LifecycleProvider来管理生命周期的管理:保存当前View的生命周期
currentState:当前状态保存当前生命周期状态,根据当前生命周期状态返回对应的
集合:保存生命周期状态接口(ILifeCycler),谁往里面注册就通知谁(生命周期)
lifeState:生命周期状态,外部提供方法改变该状态,从而走对应的生命周期方法

LifeCyclerOwner来获取Provider

BaseActivity和BaseFragment(BaseView):实现LifeCyclerOwner获取Provider,持有一个lifecyclerProvider来控制生命周期变化,调用该provider来改变生命周期状态来匹配presenter中的生命周期状态。—owner给对用的view传递给presenter对应的生命周期状态

VIew:持有presenter,通过onwer获取相应provider来获取生命周期变化的感应(通过添加数据变化监听)

LifeCylce

使用生命周期感知型组件处理生命周期:
生命周期感知型组件可执行操作来响应另一个组件(如 Activity 和 Fragment)的生命周期状态的变化。这些组件有助于您编写出更有条理且往往更精简的代码,此类代码更易于维护。

一种常见的模式是在 Activity 和 Fragment 的生命周期方法中实现依赖组件的操作。但是,这种模式会导致代码条理性很差而且会扩散错误。通过使用生命周期感知型组件,您可以将依赖组件的代码从生命周期方法移入组件本身中。

androidx.lifecycle 软件包提供了可用于构建生命周期感知型组件的类和接口 - 这些组件可以根据 Activity 或 Fragment 的当前生命周期状态自动调整其行为。

Lifecycle 是一个类,用于存储有关组件(如 Activity 或 Fragment)的生命周期状态的信息,并允许其他对象观察此状态。

Lifecycle 使用两种主要枚举跟踪其关联组件的生命周期状态:

事件
从框架和 Lifecycle 类分派的生命周期事件。这些事件映射到 Activity 和 Fragment 中的回调事件。
状态
由 Lifecycle 对象跟踪的组件的当前状态。

lifecycleOwner: getLifeCycle (Activity和Fragment)
LifecycleOwner 是单一方法接口,表示类具有 Lifecycle。它具有一种方法(即 getLifecycle()),该方法必须由类实现。如果您尝试管理整个应用进程的生命周期,请参阅 ProcessLifecycleOwner。

LifeCycle:类似于provider。

LifecycleObserver:观察者。

基本使用一

获取activity和fragment中owner。
通过owner获取lifecycle调用addObserver(new LifecycleObserver)方法 实现观察者模式方法接口

public class MyObserver implements LifecycleEventObserver {
	//被动通知
    @Override
            public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
                switch (event){
                    case ON_START: //在onstart的时候调用
                }
            }
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

//主动感知
myLifecycleOwner.getLifecycle().currentState

源码解析

addObserver 通过包装成ObserverWithState(状态) 再包装成map集合(状态和方法)通过集合调用,dispatchEvent分发事件 调用 onStateChange方法(owner,event状态)当状态改变时,就会通知到你使用生命周期感知的地方

基本使用二

public class MyObserver implements LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void connectListener() {
        ...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void disconnectListener() {
        ...
    }
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

源码解析

view层生命周期通知lifecycle

view层实现lifecycleowner接口 -->直接创建LifeCycleRegistry(this).
当生命周期发生变化的时候调用lifecycleRegistry的handleLifecycleEvent处理相应的事件

Lifecycle如何通知观察者变化

addObserver,通过一个集合。 遍历集合 observer调用dispatchEvent方法 调用onStateChange方法。(先观察就通知谁)
生命周期变化的时候,将event事件转化state状态 sync方法(backwardPass逆序迭代)然后去分发事件onStateChange(owner:当前activity,event:当前事件)

注解的方式: @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
元注解,运行时注解 (Lifecycling) 在 new ObserverWithState时候进入 然后处理annotation 注解。(classeInfoCache)event获取Lifecycle.Event.ON_PAUSE
event ----》对应方法 来封装集合中eventToHandler
调用时候:ReflectiveGenericLifecycleObserver通过反射来调用 所以调用该方法中onStateChange方法(source,event,mWrapped) —>invokeMethodsForEvent方法一个是event和ON_ANY。通过eventToHandler的event(key)获取方法,并调用方法

方法(owner,event,source)获取这三个参数

LiveData

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态(STARTED 或 RESUMED 状态)的应用组件观察者。

如果观察者(由 Observer 类表示)的生命周期处于 STARTED 或 RESUMED 状态,则 LiveData 会认为该观察者处于活跃状态。LiveData 只会将更新通知给活跃的观察者。为观察 LiveData 对象而注册的非活跃观察者不会收到更改通知。

您可以注册与实现 LifecycleOwner 接口的对象配对的观察者。有了这种关系,当相应的 Lifecycle 对象的状态变为 DESTROYED 时,便可移除此观察者。这对于 Activity 和 Fragment 特别有用,因为它们可以放心地观察 LiveData 对象,而不必担心泄露(当 Activity 和 Fragment 的生命周期被销毁时,系统会立即退订它们)。

LiveData优势

  • 确保界面符合数据状态
    LiveData 遵循观察者模式。当底层数据发生变化时,LiveData 会通知 Observer 对象。您可以整合代码以在这些 Observer 对象中更新界面。这样一来,您无需在每次应用数据发生变化时更新界面,因为观察者会替您完成更新。
  • 不会发生内存泄漏
    观察者会绑定到 Lifecycle 对象,并在其关联的生命周期遭到销毁后进行自我清理。
  • 不会因 Activity 停止而导致崩溃
    如果观察者的生命周期处于非活跃状态(如返回栈中的 Activity),则它不会接收任何 LiveData 事件。
  • 不再需要手动处理生命周期
    界面组件只是观察相关数据,不会停止或恢复观察。LiveData 将自动管理所有这些操作,因为它在观察时可以感知相关的生命周期状态变化。
  • 数据始终保持最新状态
    如果生命周期变为非活跃状态,它会在再次变为活跃状态时接收最新的数据。例如,曾经在后台的 Activity 会在返回前台后立即接收最新的数据。
  • 适当的配置更改
    如果由于配置更改(如设备旋转)而重新创建了 Activity 或 Fragment,它会立即接收最新的可用数据。
  • 共享资源
    您可以使用单例模式扩展 LiveData 对象以封装系统服务,以便在应用中共享它们。LiveData 对象连接到系统服务一次,然后需要相应资源的任何观察者只需观察 LiveData 对象。如需了解详情,请参阅扩展 LiveData。

基本使用

  1. 创建 LiveData 的实例以存储某种类型的数据。这通常在 ViewModel 类中完成。
  2. 创建可定义 onChanged() 方法的 Observer 对象,该方法可以控制当 LiveData 对象存储的数据更改时会发生什么。通常情况下,您可以在界面控制器(如 Activity 或 Fragment)中创建 Observer 对象。
  3. 使用 observe() 方法将 Observer 对象附加到 LiveData 对象。observe() 方法会采用 LifecycleOwner 对象。这样会使 Observer 对象订阅 LiveData 对象,以使其收到有关更改的通知。通常情况下,您可以在界面控制器(如 Activity 或 Fragment)中附加 Observer 对象。

ViewModel(Presenter)中

//声明livedata数据
MutableLiveData<T> mData;  //T是要保存的数据类型
//在需要数据更新的提放
mData.postvalue(T);//mData.setvalue(T);当前线程,post:主线程

在Activity/Fragment中添加观察者

mViewModel.mData.observe(this,new Observer<T>() {
            @Override
            public void onChanged(T t) {

            }
        });  //this:owner  ,Obersver当数据发生变化时需要如何操作
	
mForeverObserver=new ForeverObserver();//继承于Observe实现onchange方法
 mData.observeForever(mForeverObserver);

  @Override
    protected void onDestroy() {
        super.onDestroy();
        mData.removeObserver(mForeverObserver);//onDestory不更新
    }

共享数据基本使用

写一个类 继承于LiveData ,写成单例 懒加载(需要时加载)
复写postvalue方法

和之前的使用时一样操作viewModel中 数据改变postvalue和view中监听数据变化

需要共享数据则在共享的view 监听数据变化。

源码解析(观察者模式)

LiveData() 抽象类 —MutableLiveData()实现类‘
方法:observe(owner,observer) --观察者监听数据
observeForever()

LiveData如何确保数据在主线程更新

postvalue()时
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
调用setvalue方法

LiveData如何通知观察者更新

observeForever中:AlwaysActiveObserver(observer);
observe中:LifecycleBoundObserver(owner, observer);

//只有可见才更新返回true
boolean shouldBeActive() {
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

  boolean shouldBeActive() {
            return true;
        }

setvalue时:dispatchValue() considerNotify(iterator.next().getValue());
先判断版本然后 调用onChanged方法

observer.mObserver.onChanged((T) mData);

LiveData如何感知生命周期的变化

observe方法中

 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);

  owner.getLifecycle().addObserver(wrapper);

new LifecycleBoundObserver(owner, observer);这个类具有感知生命周期的作用
它实现了lifecycleEvent(即LifeCycle的事件通知)

在活跃的状态更新数据

ViewModel

业务逻辑类(ViewModel)
架构组件为界面控制器提供了 ViewModel 辅助程序类,该类负责为界面准备数据。在配置更改期间会自动保留 ViewModel 对象,以便它们存储的数据立即可供下一个 Activity 或 Fragment 实例使用。例如,如果您需要在应用中显示用户列表,请确保将获取和保留该用户列表的责任分配给 ViewModel,而不是 Activity 或 Fragment

生命周期

不会被destory,除非view层被destory了。

基本使用

首先继承于ViewModel的一个类 InstanceViewModel

然后再View层使用

 InstanceViewModel viewModel=new ViewModelProvider(this).get(InstanceViewModel.class);
//ViewModel 持有LiveData对象
LivaData<T> mData;

源码解析

ViewModelProvider(this).get(InstanceViewModel.class);
ViewModelStoreOwner:Fragment/Activity实现了该接口 返回一个ViewModelStore

ViewModelStore:内部是一个集合HashMap<String,viewModel>

viewmodel创建

从view层获取一个存储ViewModel的集合(mViewModelStore)
创建之前,先从mViewModelStore里获取,如果有就返回,如何没有就创建新的,并且会保存再mViewModelStore中。
所以,多次使用同一个view去创建的viewmodelProvider获取到viewModel不会重复

Fragment共享逻辑和共享数据
有这个场景。
如果我们在多个Fragment中,使用宿主Activity作为viewModelOwner来创建viewmodel是同一个。

view Model如何跟生命周期挂钩

mViewModelStore的clear方法中时

 getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // Clear out the available context
                    mContextAwareHelper.clearAvailableContext();
                    // And clear the ViewModelStore
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

数据如果需要清空:重写 onCleared()方法。//ondestory时(不写的话跟viewModel的生命周期相同)

MVVM

例子: 特惠界面
主要类:OnSellActivity (view),OnSellViewModel(vm/viewmodel),OnSellRepository(model/romote data source)

获取数据:Romote data source(Retrofit)
类:ApiService(接口类),RetrofitClient(创建Retrofit BaseUrl Gson转换器 Okhttp),ResultData(处理返回结果统一的类,根据code是否成功的验证码,成功返回数据T,失败抛出异常ApiException),ApiException(请求错误异常)

数据类:LoadState(枚举类根据网络状态和获取情况),OnSellData(数据)

功能(viewmodel):加载数据,加载更多。

代码

 类似资料: