基于 Android Architecture Components 的 MVVM 浅析

0、前言

官方文档永远是最好的学习资料:
Android Jectpack
Android Jetpack: LiveData 和 Lifecycle 介绍 | 中文教学视频
Android Jetpack - ViewModel | 中文教学视频
Android Jetpack Room | 中文教学视频
深刻了解还需多看文档和源码。java

一、简介

1.一、AAC 是什么

AAC (Android Architecture Components) 是谷歌推出的一套包含在 Jetpack 中的,帮助咱们构建稳健、可测试且易维护应用的组件库,主要包括 LifecycleLiveDataViewModelRoomWorkManager 等一系列好用的工具。注意,AAC 并非一种新的架构,只是一套和架构相关的工具,能够帮助你更加简单高效的构建你想要的架构。android

1.二、AAC 与 MVVM

MVC (Model-View-Controller)、MVP (Model-View-Presenter) 和 MVVM (Model-View-ViewModel) 在 Android 中的应用大概能够归纳为下图(架构分层因人而异,这里只是我本身的一些理解)
git


在 MVP 的架构中,View 层和 Presenter 层相互引用对方,Presenter 层收到 View 层的动做或者拿到 Model 层的数据后主动调用 View 的一些方法,显示相应的结果。Presenter 层就像个全职保姆同样,上有 View 层要处理动做和显示,下有 Model 层要请求和处理数据,中间本身还要处理业务逻辑。咱们通常须要定义 IViewIPresenter 之类的接口,而后 View 层和 Presenter 层相互持有对方的引用,这样就存在不少问题,好比:

  • View 和 Presenter 解耦不完全,Presenter 须要具体知道 View 层的能力
  • 由于 View 层和 Model 层之间的通信和其余业务层面的大小事务都由它来处理,会致使 Presenter 过分膨胀
  • View 层的生命周期和 Presenter 层不一致,以及内存泄漏等问题
    注意 弱引用只能解决内存泄露的问题,没法解决生命周期的问题,好比 Activity 已经 onDestroy,但并无被回收的场景
  • 扩展性差,增删 View 层或变动业务要改动不少代码

MVVM 采用 View 层与 ViewModel 层的数据绑定的方式,View 层监听相应的数据,并在数据变动时本身更改视图,从而很好地解决了上述问题:github

  • View 层和 ViewModel 层松耦合,ViewModel 层不须要持有具体的 View,也不须要知道 View 层的任何东西
  • ViewModel 层很轻,ViewModel 层只须要把新的数据通知到各个 View,而不关心 View 的显示
  • 因为 ViewModel 层不直接引用 View 层,生命周期更好处理
  • ViewModel 层不关心 View 层的变动,不也不关心 View 的数量,甚至不关心监听的是否是 View

可见 MVVM 更为先进好用,实现 MVVM 的方法也有不少,而 AAC 就是为 MVVM 而生的,经过 AAC 中的 LiveDataViewModel 等组件,咱们能够很容易地在 Android 上实现 MVVM。它的 Lifecycle 组件可让咱们更有效的管理 app 内的各类生命周期,在配置变动时保存数据,避免内存泄漏,更方便地把数据加载到 UI 中;LiveData 用来构建一个能够在数据变动时通知视图的数据对象,且具备生命周期感知的能力;ViewModel 能够存储 UI 相关的数据,并保证在配置变动时不会丢失。数据库

二、基于 AAC 的 MVVM 简单用法

2.一、LiveData

LiveData 是一个可观察的数据持有类,并且它能够感知其余应用组件 (如 ActivityFragmentService) 的生命周期,这种感知可确保 LiveData 仅更新生命周期处于激活状态(STARTED 和 RESUMED)的观察者。它的主要优势有:缓存

  • UI 与数据同步,利用观察者模式,能够在数据变化时通知 UI
  • 不存在内存泄露,会在观察者对应的生命周期结束后自动移除观察者
  • 不会更新非激活状态(STOPPED)状态的 UI,以避免形成崩溃(Fragment Transaction)
  • 不须要手动处理生命周期事件
  • UI 从非激活状态切换到激活状态时,会收到 LiveData 的最新数据,数据预加载再也不须要考虑 View 的状态
  • ActivityFragment 重建时也会收到通知(须要和 ViewModel 配合使用)

简单用法。假设咱们的 MainActivity 的视图中有一个 Button 和一个 TextView 来实现一个简单的计数器,还有一个计数值的 LiveData。点击 Button 会更新计数值,而 TextView 监听该 LiveData 来更新本身。示例分析以下:网络

public class MainActivity extends AppCompatActivity {
    // 一、MutableLiveData 是什么
    private MutableLiveData<Integer> mLiveData = new MutableLiveData<>();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 初始化工做
        // ...
        
        mLiveData.setValue(0);
        
        // 二、LiveData.observe() 的参数都是什么意思
        // public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
        mLiveData.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(@Nullable final Integer count) {
                // Update the UI, in this case, a TextView.
                mTextView.setText(newName);
            }
        });
        
        // 三、LiveData 的值怎么更新
        mButton.setOnClickListener(v -> mLiveData.setValue(mLiveData.getValue() + 1));
    }
}
复制代码

一、首先 LiveData 是一个抽象类,且 setValuepostValue 两个更新 value 的方法都是 protected 的,而 MutableLiveData 继承 LiveData,重写这两个方法,并将访问权限设置为 public架构

二、public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer)
第一个参数 LifecycleOwner 是持有生命周期的对象,好比 ActivityFragment,可让 LiveData 能够感知它的生命周期,并在生命周期结束时将其移除,避免内存泄漏;第二个参数 Observer 是一个接口,它只有一个方法 void onChanged(T t)LiveData 会在数据更新时调用这个函数来通知 UI 层的观察者。并发

三、setValuepostValue 两个均可以更新 value,不一样之处在于 setValue 只能在主线程调用,而 postValue 能够用于子线程(注意:短期内屡次 postValueLiveData 只会保留最后一个来通知观察者)。app

固然,这只是LiveData 用法的简单说明,实际项目中若是这样用会有些问题:

  • 把数据相关的东西放在了 View 层,固然咱们能够单独抽一层放 LiveData 来解决这个问题
  • 在配置变动(如屏幕旋转)时,ActivityFragment 会重建致使数据丢失,这个问题固然能够经过 onSaveInstanceState 来保留和恢复数据;
  • 若是多个 View 都须要一样的数据源或者相互通信,难以保证拿到同一个 LiveData,单例能够解决这个问题,但数据源不在被须要时也没法回收资源。

上面说的这些问题均可以经过某些手段解决,可是都不是很优雅,而谷歌固然考虑到了,这些问题在接下来的 ViewModel 中,都获得了很好的解决。

2.二、ViewModel

ViewModel,顾名思义,是用来存储和管理 View 相关数据的,而 AAC 中的 ViewModel 还能够感知生命周期,能够在配置变动(如屏幕旋转)时自动保存数据,还能够在生命周期真的结束时触发回调来清除没必要要的请求,以避免内存泄漏。而做为 MVVM 的中间层,它还肩负着响应 View 层的动做,以及操做 Model 层请求数据的任务。ViewModel 的生命周期以下图所示:


注意ViewModel 因为生命周期是长于 View 层( ActivityFragmentView)的,不能(也不须要)持有 View 层的任何东西,若是要使用 context 能够继承 AndroidViewModel,它内部持有 Application 的 context。
简单用法。

public class MyViewModel extends ViewModel {
    // ...
    
    public List<User> getUsers() {
        return users;
    }

    public void loadUsers() {
        // 请求 users 数据.
    }
    
    // 一、调用时机
    @Override
    protected void onCleared() {
        // 清除没必要要的请求 
    }
}

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // MyActivity 重建时仍是能拿到同一个 MyViewModel
        // 二、ViewModelProviders.of 参数
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.loadUsers();
    }
}
复制代码

一、ViewModelonCleared 函数会在持有它的对象的生命周期结束时调用,以避免异步请求形成 ViewModel 的内存泄露;

二、public static ViewModelProvider of(@NonNull FragmentActivity activity)public static ViewModelProvider of(@NonNull Fragment fragment),传入的参数能够是 ActivityFragment,其内部会拿到 ActivityFragmentViewModelStore,顾名思义就是存储 ViewModel 的地方,其内部也只是一个 HashMap<String, ViewModel>,键是内部用 ViewModelClass 的名字拼出的字符串。

利用 ViewModelStore 存储 ViewModel 能够十分方便地管理 ViewModel ,前面说的 ViewModel 能够在配置变动后存活,其实就是在重建保存状态时,保存下了 ViewModelStore,实现方式和保存 Fragment 相似(Bundle 保存的数据是有限的,为了在配置变动时保存大量数据,也能够用 Fragment 来存)。利用 ViewModelStore 存储 ViewModel 的方式还能够方便 Fragment 之间的通信和数据同步,只要多个 Fragment 隶属于 同一个 Activity,他们就能够经过 ActivityViewModelStore 拿到同一个 ViewModel

2.三、MVVM

虽然 LiveDataViewModel 单独拿出来用也是强有力的工具,谷歌推出 AAC 的目的明显不只仅是一个工具,这一整套服务于的架构相关的组件能够帮助咱们轻松的打造 MVVM,并且都带着生命周期感知能力。接下来经过一个计数器例子,简单介绍下使用方法。

public class CountViewModel extends ViewModel {
    private final MutableLiveData<Integer> mCountLiveData = new MutableLiveData<Integer>();
    
    public LiveData<Integer> getCountLiveData() { return mCountLiveData; }

    public void loadCount() {
        // 能够经过网络或数据库请求数据
        request.enquen(response -> { 
            if (response.isSuccess()) {
                mCountLiveData.postValue(response.data);
            }
        });
    }
    
    public void countDown() {
        // 减少计数
        if (mCountLiveData.getValue() != null) {
            mCountLiveData.setValue(mCountLiveData.getValue() - 1);
        } else {
            loadCount();
        }
    }
    
    public void countUp() {
        // 增大计数
        if (mCountLiveData.getValue() != null) {
            mCountLiveData.setValue(mCountLiveData.getValue() + 1);
        } else {
            loadCount();
        }
    }
}

public class ActionFragment extends Fragment {
    //...
    
    @Override
    public void onViewCreated(View v, Bundle savedInstanceState) {
        final CountViewModel countViewModel =  ViewModelProviders.of(getActivity()).get(MyViewModel.class);
        // 改变计数值
        v.findViewById(R.id.up_buttonn).setOnClickListener(v -> {
            countViewModel.countUp();
        });
        v.findViewById(R.id.down_buttonn).setOnClickListener(v -> {
            countViewModel.countDown();
        });
    }
    
    //...
}

public class ShowCountFragment extends Fragment {
    //...
    
    @Override
    public void onViewCreated(View v, Bundle savedInstanceState) {
        final TextView count = v.findViewById(R.id.count_text_view);
        // 这里的 getActivity() 是为了拿到同一个 CountViewModel
        ViewModelProviders.of(getActivity())
            .get(CountViewModel.class)
            .getCountLiveData()
            // 这里的 this 是为了让 LiveData 绑定观察者的生命周期
            .observe(this, data -> {
                count.setText(data);
            });
    }
    
    //...
}
复制代码

在该例子中,CountViewModel 中有一个 mCountLiveData 用于保存计数值,还有一组用于更新计数值的方法;ActionFragmentShowCountFragment 位于同一个 Activity 中,这样能够保证二者拿到同一个 CountViewModelActionFragment 的两个按钮用于增减计数,而 ShowCountFragment 则监听并显示计数值。

这样一个简单的 MVVM 架构的计数器就搭建好了。View 层的 ShowCountFragment 绑定 ViewModel 层的 mCountLiveData,并在数据变动时更新视图,而 ViewModel 层不须要直接持有任何 View 层的引用(LiveData 持有的观察者在 View 层,可是会自动根据生命周期来移除),ViewModel 也不关心监听数据的 View 的数量和类型,View 拿到数据后显示什么东西也都无所谓,多一个 View 只不过是多了一个观察者而已,并且多个 View 不须要借助其余工具(EventBus、RxBus 等事件总线)就能够经过 ViewModel 实现通讯。

对于数据源比较多的场景,谷歌建议咱们单独抽出 Repository 层(其实就是 Model 层)用于处理数据来源(缓存、数据库或网络),并向上返回数据的 LiveData(如 Room)来保持数据的同步,整个架构图以下图所示:

MVVM

三、进一步了解 AAC

**配合源码使用,效果更佳!**特别推荐使用 androidx 来看源码,会清晰方便不少。

3.一、Lifecycle

View 层的动态性很强,各个界面切换、视图元素交替出现等都伴随着生命周期的变化,而下层元素的生命周期每每要长于 View 的生命周期,为了避免形成资源浪费和内存泄漏,咱们时常须要手动管理 View 的生命周期。好比咱们有一个显示当前位置的 Activity,咱们须要在 onStart 时开始监听位置信息,并在位置变化时更改视图,在 onStop 时注销监听。


手动管理 ActivityFragment 的生命周期是一件十分繁琐并且低效的事情,为了更有效地管理生命周期,许多第三方库(例如 Glide、RxLifecycle)都将监听与分发生命周期地任务交给 Frgament,由于只要将 Frgament 塞进 Activity 中, Frgament 就能与 Activity 生命周期同步,而后经过自定义的 Frgament 将生命周期事件发送出来。AAC 中的 Lifecycle 组件也是经过这种方式和观察者模式实现了生命周期地自动管理。

Lifecycle 组件主要有 LifecycleLifecycleObserver 和一套相关地类组成。Lifecycle 定义了一系列生命周期地状态和事件,其惟一子类 LifecycleRegistry 则实现了一个做为生命周期被观察者所具备的能力,在生命周期变化时向观察者们分发事件。LifecycleObserver 是一个起标识做用地接口,它的子接口 LifecycleEventObserveronStateChanged 方法在 LifecycleRegistry 分发生命周期时会被回调。

如今问题来了:

  • 咱们怎么拿到 Lifecycle

Lifecycle 的持有者都会实现 LifecycleOwner 接口,重写 Lifecycle getLifecycle();方法,返回本身持有的生命周期对象 LifecycleRegistryActivityFragment 都实现了该接口。

  • Lifecycle 的生命周期事件从哪里来,和以前说的 Frgament 有什么关系?

LifecycleOwner 的实现类既然持有 Lifecycle,那确定就会发送事件啦。Frgament 的话比较简单,内部保存了一个 mLifecycleRegistry,并在本身的生命周期事件中调用 mLifecycleRegistryhandleLifecycleEvent 方法将事件传递给 LifecycleRegistryActivity 本身也持有一个 mLifecycleRegistry,可是它不本身发送事件,而是把任务交给了一个叫 ReportFragmentFragment,其实现也很简单,就是在本身的生命周期事件中拿到 ActivitymLifecycleRegistry,而后再进行分发。

  • LifecycleObserver 怎么用

须要监听 Lifecycle 的对象实现这个接口,而后在 onStateChanged 方法中根据不一样的生命周期作出相应的动做。好比前面说的监听位置信息的例子,咱们就能够单独抽出一个对象来专门作监听操做,实现 LifecycleObserver 接口,并本身处理生命周期事件。

class MyLocationListener implements LifecycleObserver {
    private boolean enabled = false;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
       //...
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void start() {
        if (enabled) {
           // connect
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop() {
        // disconnect if connected
    }
}
复制代码

3.二、ViewModel

这里咱们来扒一扒源码,看 ViewModel 是如何建立、如何挺过配置变动,又是什么时候真正的消失的。

  • ViewModel 的建立

前面咱们已经知道 ViewModel 都保存在 ViewModelStore 中,那只要知道 ViewModelStore 如何被建立、保存与销毁就行。在 ComponentActivitygetViewModelStore 方法能够看到 ViewModelStore 的建立过程。

if (mViewModelStore == null) {
    NonConfigurationInstances nc =
            (NonConfigurationInstances) getLastNonConfigurationInstance();
    if (nc != null) {
        // Restore the ViewModelStore from NonConfigurationInstances
        mViewModelStore = nc.viewModelStore;
    }
    if (mViewModelStore == null) {
        mViewModelStore = new ViewModelStore();
    }
}
复制代码

能够看到 ViewModelStore 是从一个叫 NonConfigurationInstances 的实例中拿的,若是拿不到说明以前没经历过配置变动,那就 new 一个出来。接着看

// ComponentActivity 里的
static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}
复制代码

NonConfigurationInstances 除了保存 ViewModelStore 还存着 custom 用于保存咱们本身定制的数据,这个能够经过重写 onRetainCustomNonConfigurationInstance 方法来用。再来看下 getLastNonConfigurationInstance

public Object getLastNonConfigurationInstance() {
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}
// 这个是 Activity 中的,和 ComponentActivity 里的那个不同
static final class NonConfigurationInstances {
    Object activity;
    HashMap<String, Object> children;
    FragmentManagerNonConfig fragments;
    ArrayMap<String, LoaderManager> loaders;
    VoiceInteractor voiceInteractor;
}
复制代码

是在 ActivityNonConfigurationInstances 中的 activity,经过 NonConfigurationInstances 咱们也能大体看出 Fragment 在配置变动的时候会被保存到 FragmentManagerNonConfig 中。

  • 接下来看如何挺过配置变动的

ComponentActivityonRetainNonConfigurationInstance 中会分别拿咱们定制的 customViewModelStore,而后返回建立好的 NonConfigurationInstances。而 onRetainNonConfigurationInstance 会在配置变动时被 LocalActivityManagerdispatchRetainNonConfigurationInstance 方法中调用,从而保存状态信息。至此咱们就知道保存 ViewModelStore 的流程,再继续深刻源码就没法自拔了。

  • 最后看下何时真正的销毁 ViewModel,调用它的 onCleared
getLifecycle().addObserver(new GenericLifecycleObserver() {
    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            if (!isChangingConfigurations()) {
                getViewModelStore().clear();
            }
        }
    }
});
复制代码

ComponentActivity 的构造函数中有这么一段代码,恰好用到了咱们前面说的 LifecycleLifecycleObserver,在 ON_DESTROY 时判断下是不是配置变动,不是的话就调用 ViewModelStoreclear 方法,会清除 ViewModelStore 中保存的 ViewModel,并调用他们的 clear 方法,进而调用到 onCleared

至此,Activiy 中的 ViewModel 相关生命周期已经分析完了,Fragment 中也大同小异,主要涉及 FragmentManagerImplFragmentManagerViewModel 等一些类,感兴趣的能够顺着 ViewModelStore 的思路,本身深刻了解下。

3.三、LiveData 扩展用法

观察者模式的那套东西均可以玩一些骚操做,责任链、事件总线什么的,LiveData 做为一个可观察对象,固然也能够,这里简单分析两个。

首先了解下一个叫 MediatorLiveData 的对象,它继承自 MutableLiveData,经过 public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) 方法实现了增长其余 LiveData 做为本身事件源的功能,源 LiveData 更新时,会调用传入的 ObserveronChanged 方法作处理。MediatorLiveData 是利用 public void observeForever(@NonNull Observer<? super T> observer) 方法来添加源的,这个方法不须要传 LifecycleOwner,可是须要手动移除观察者,不过不用担忧,MediatorLiveData 已经帮咱们作了。若是 MediatorLiveData 已经没有任何观察者,它会自动调用源 LiveDataremoveObserver 方法来移除对源 LiveData 的监听,以防本身内存泄漏。

利用 MediatorLiveData 对象,咱们能够作一些事件变换的操做,TransformationsmapswitchMap 就是经过该对象实现的。

以前的事件总线都须要手动处理生命周期的问题,EventBus 须要手动注销,RxBus 须要 RxLifecycle 的扩展库来监听生命周期。有了 LiveData,咱们彻底能够用不多的代码撸一个具备生命周期感知能力的事件总线,实现很简单(一个简单但实用的 LiveDataBus 只须要一百行代码左右),网上也有不少开源的库,这里只讲下大体思路。

要想作事件总线,核心就是发送方和接收方拿到同一个可观察对象,在这里就是同一个 LiveData。最简单的方法就是定义一个单例类,假设叫 LiveDataBus,里面放一个 Map<Class<?>, MutableLiveData<?>> 来保存全部的事件类型 Class 和对应的 LiveData,这样就能经过事件的 Class 拿到对应的惟一 LiveData。这里有几个须要注意的地方:

  • Map 的并发问题,由于来拿 LiveData 的可能多个线程的,因此要作好同步工做,再考虑到可见性,建议用 ConcurrentHashMap
  • Map 里存的 ClassMutableLiveData 都被擦出了泛型(不一样事件的 Class<T> 里泛型确定不同呀),因此要本身保证二者的泛型一致,能够定义一个保存 Class<T>MutableLiveData<T> 的带泛型 <T> 的类,在里面保证一致;
  • LiveDataBus 中的 LiveData 不会被释放,也就致使它里面的数据不会被释放,能够在事件不用时发送一个空事件;
  • 全局的事件总线会形成业务间的耦合,并且很差调试,除非关键事件,不要滥用。

注意ViewModel 已经可以解决不少场合的通讯问题,并且能在不用时释放掉,因此能用 ViewModel 通讯的就不要用事件总线,除非两个 Activity 必须经过某种方式进行通信,也要先考虑下单例的 LiveData,实在不行再用事件总线。

最后再强调一遍,不要滥用事件总线

3.四、LiveData 源码分析

LiveData 源码很少,这里只简单分析几个 LiveData 的特性。

  • 如何在观察者生命周期结束自动移除观察者

LiveData 的订阅方法看起

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    // ...
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    // ...
    owner.getLifecycle().addObserver(wrapper);
}
复制代码

能够看到 LiveData 不只是一个可观察对象,同时仍是一位观察者,它所观察的就是 ActivityFragment 等持有 LifecycleLifecycleOwner,固然也要把观察本身的观察者保存下来,接下来看下 LifecycleBoundObserver 这个观察者是怎么处理 Lifecycle 的。首先它继承自 ObserverWrapper 这是一个会根据 Lifecycle 是否处于激活状态决定是否分发数据的观察者,这里先跳过,LifecycleBoundObserver 还实现了 GenericLifecycleObserver 接口,其实就是前面说过的 LifecycleEventObserver,它的生命周期状态回调函数以下:

// LifecycleBoundObserver 的方法
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

// LiveData 的方法
public void removeObserver(@NonNull final Observer<? super T> observer) {
    // ...
    ObserverWrapper removed = mObservers.remove(observer);
    // ...
    removed.detachObserver();
    removed.activeStateChanged(false);
}

// LifecycleBoundObserver 的方法
void detachObserver() {
    mOwner.getLifecycle().removeObserver(this);
}
复制代码

onStateChanged 在判断 Lifecycle DESTROYED 的时候调用 LiveDataremoveObserver,首先将观察 LiveData 的观察者移除,防止内存泄漏,以后再调用LifecycleBoundObserverdetachObserver 将本身从 LifecycleOwner 的观察者中移除,自此将相互之间的观察状态接触。

  • 观察者的生命周期从非激活态到激活态时是怎么收到通知的

作预加载的时候,咱们能够在 ActivityFragment 建立时直接请求数据,塞到 LiveData,而后只要生命周期处于激活状态,无论何时监听 LiveData,都能收到最新的消息。咱们再来看一下 LifecycleBoundObserveronStateChanged 方法,它在最后调用了父类的 activeStateChanged(shouldBeActive()) 方法,来大体看一下

void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    // immediately set active state, so we'd never dispatch anything to inactive
    // owner
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) {
        // 该方法是 LiveData 的
        onActive();
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) {
        // 该方法是 LiveData 的
        onInactive();
    }
    if (mActive) {
        dispatchingValue(this);
    }
}
复制代码

它首先会根据当前的激活状态进行去重,而后会根据 LiveData 的观察者处于激活状态的数量和新的状态判断是否调用 onActiveonInactive,这两个也是 LiveData 的重要回调,不过都好理解,就不在细说了。最后会判断如今是不是激活状态,是的话就调用 LiveDatadispatchingValue 方法,顾名思义就是 LiveData 向其观察者发送通知。而 dispatchingValue 接收一个 ObserverWrapper 的参数,若是不为空就是说只用通知这个特定的观察者,不然通知全部处于激活的观察者。

  • setValuepostValue

setValue 直接改变当前的值,而后调用 dispatchingValue(null) 来通知全部激活状态的观察者,不过必须在主线程调用不然会抛异常。由于其余线程也均可以直接改变当前值的话会形成并发,加锁的话又会影响性能。

因此就又搞了一个 postValue,它首先在拿到同步锁的状况下把值存到 mPendingData,而后向主线程的 Handler 抛一个更新当前值的 mPostValueRunnable,这个 mPostValueRunnable 在执行时也是先拿同步锁,而后调用 setValue(如今在主线程)把 mPendingData 设置到当前值。在 mPostValueRunnable 抛出去以后且还未执行前,若是再次调用 postValue 就又会修改 mPendingData 的值,而不会再次向 Handler 抛一次 mPostValueRunnable,这样就致使了后设置的值覆盖掉前面设置的,最后只会向观察者们通知最新的值。这个是须要注意的点,谷歌可能认为既然只是在主线程更新 View,那你拿最新的值就行,其余的都无所谓,固然这样也起到流量控制的做用,防止短期内过多的事件触发无用的回调。

四、总结

谷歌推出的 AAC 库很好的解决了平常使用中的生命周期问题,使咱们能够专心于业务层面的设计,而不须要再为生命周期等问题担心。LiveDataViewModel 确实好用,但用的时候也有须要注意的地方,ViewModel 层实际应用中要上承 View 层,提供必要的动做和数据,下接 Model 层,作好数据处理,都有不少须要考虑的地方,以后有时间再谈谈我在使用 AAC 的路上的经验和总结。
博客的 Github 仓库 欢迎你们 Start & Fork !

相关文章
相关标签/搜索