• 2022年Android面试之Jetpack(AAC框架)篇


    前言

    谷歌官方推的Jetpack框架也已经有很长一段时间了,基本上新开的项目都会使用MVVM + kotlin + 协程的架构去搭建一些新的项目或者重构,因此面试中AAC框架在面试或多或少会提到,本篇主要是对几个常用框架进行高度概括,具体需要自行结合源码查阅

    Lifecycle

    • 功能:抽离Activity生命周期,提供API进行监听(观察者模式),使用状态模式保存了当前的状态以及前后两步的事件
    • 注意点:非线程安全,在主线程调用
    • 源码实现:在ComponentActivity会注入一个ReportFragment,里面会对生命周期进行分发(类似Glide)
    • 注解(OnLifecycleEvent)使用原理:
    • 2.4 之后已废弃,推荐设置监听的方式实现
    • 实现LifecycleObserver接口,这个接口是个空接口,之后在需要的方法标记OnLifecycleEvent注解,例如 @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) ,然后调用 Lifecycle#addObserver 方法,里面会构造一个 ObserverWithState,在ObserverWithState的构造函数会调用 Lifecycling#lifecycleEventObserver,通过注解反射获取到所有标注了的方法,在分发生命周期的时候会通过反射调用该方法
    • 通过ObserverWithState 以及 Lifecycling 统一了注解/继承 接口,以便调用;在其dispatchEvent方法会获取

    状态与事件

    分发流程image-20220524174909957.png

    LiveData

    • 功能:
    1. 具有观察生命周期能力的数据,本身观察Lifecycle,并且提供API作为被观察者监听数据变化(仅在生命周期有效时触发)
    2. 作为事件总线使用 —— LiveDataBus

    源码分析

    Observe 方法

    • 首先根据调用的observe或者observeForever,对监听对象进行一次包装,然后添加到观察者集合,这里的包装是为了后续的统一操作(判断是否活跃等);一个监听对象只能对应一个lifecycle
    • 接着如果是observeForever,会调用检查一次值状态进行分发(黏性);如果是observe方法,则会封装成LifecycleBoundObserver(实现了LifecycleEventObserver),并添加监听Livecycle的事件,后续会根据事件决定是否分发新值(活跃状态)

    image-20220525232613966.png

    分发消息

    • postValue(切换到主线程再调用setValue)
    • setValue

    无论是postValue还是 setValue,都会走到setValue,首先会更新LiveData的值,然后把版本号加一,再遍历所有观察者,判断生命周期并调用符合条件的观察者的onChange方法,注意这个遍历的过程,当所绑定的生命周期状态改变时也会进行一轮判断(ObserverWrapper#activiStateChange)

    // mDispatchingValue: 是否正在分发值
    // mDispatchInvalidated 是否分发完成
    // 通过这两个状态控制分发状态 及时更新最新的值
    void dispatchingValue(@Nullable ObserverWrapper initiator) {
            // 如果正在更新值 mDispatchInvalidated 直接置为true 这样下面do while会再执行一次 更新最新的值
            if (mDispatchingValue) {
                mDispatchInvalidated = true;
                return;
            }
            mDispatchingValue = true;
            do {
                mDispatchInvalidated = false;
                if (initiator != null) {
                    considerNotify(initiator);
                    initiator = null;
                } else {
                    for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                            mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                        considerNotify(iterator.next().getValue());
                        // 说明有新值 直接中断重新开始
                        if (mDispatchInvalidated) {
                            break;
                        }
                    }
                }
            } while (mDispatchInvalidated);
            mDispatchingValue = false;
        }
        
     // 真正的把值传递出去
     private void considerNotify(ObserverWrapper observer) {
            if (!observer.mActive) {
                return;
            }
          
            // 对观察者状态再次判断
            if (!observer.shouldBeActive()) {
                observer.activeStateChanged(false);
                return;
            }
            // 避免重复调用
            if (observer.mLastVersion >= mVersion) {
                return;
            }
            observer.mLastVersion = mVersion;
            observer.mObserver.onChanged((T) mData);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    image-20220525231247043.png

    事件总线用法

    • 可以将LiveData 以Map的形式存储起来,当做事件总线使用,但是有个问题是默认的消息是黏性的(数据倒灌)
    • 解决方法:数据倒灌的原因是添加观察者的时候,此时会更新Lifecycle的状态,进一步同步值;此时可以通过反射修改Observer的Version值和LiveData的一样,这样就不会触发更新了

    image-20220526175752195.png

    ViewModel

    • 功能:在MVVM中的VM层,隔离View和Model,同时具有生命感知能力,能够在系统配置发生变更(旋转等)自动保存数据,同时提供clear方法在activity销毁的时候清除数据
    • 保存复用:利用ComponentActivity#onRetainNonConfigurationInstanceComponentActivity#getLastNonConfigurationInstance,在activity消耗重建的时候重新赋值了一个ViewModelStore,这个ViewModelStore实际上是一个存放ViewModel的Map(String-ViewModel),而在获取ViewModel的时候,也是在这个ViewModelStore去取,如果有则返回,没有的话则通过反射去创建一个并保存在这个Map中
    • 销毁监听:在ComponentActivity 创建时会注册一个LifecycleEvent监听,当收到 销毁事件且不是配置变更时 ,会调用ViewModelStore的clear方法,之后就是依次遍历调用clear的流程
    • ViewModelStore的消耗:和onClear一样也是监听了lifecycleEvent,收到销毁事件清空

    image-20220527123903985.png
    image-20220527123917221.png

    汇总图

    请添加图片描述

    常见面试题

    MVP和MVVM优势和劣势

    • MVP:从MVC中演化,进行解耦,和View层分离,减少Activity的负担;但是MVP会产生大量的接口和类文件;生命周期需要自己管理;View和P层耦合度较高,常常需要配合改动
    • MVVM:M层完全关注于数据;更加的低耦合,VM不持有View相关,而且很多业务逻辑可以放在VM层复用;但是Databinding会导致XML文件难以复用并且难以Debug
    • 最大的区别是在MVP中,P和V层是互相持有的,而在MVVM中,VM是不持有View,不再依赖View层,而是通过观察者模式观察数据变化(LiveData、DataBinding等)

    ViewModel保存在Application和ViewModelScope的区别

    生命周期的区别,一个是应用的生命周期一个是lifecycle的生命周期

    ViewModel如何保证Activity销毁后保存数据

    在Activity被销毁的时候,AMS会通过远程Binder调用 retainNonConfigurationInstances 方法,这个方法会调用onRetainNonConfigurationInstancegetLastNonConfigurationInstance 保存一些配置,其中就包括 ViewModelStore ,在重新创建Activity时,AMS会通过 AMS#attach 将这个实例重新赋值

    ViewModelProvider和ViewModelProviders

    ViewModelProviders 是早期用于创建ViewModel的,新版本已经弃用,直接使用ViewModelProvider创建,对应的ViewModelStore也是由Activity/Fragment管理

    ViewModel的保存和恢复

    见上ViewModel篇

    如何理解MVVM

    • 首先MVVM是一种架构模式,在安卓开发中,谷歌为我们提供了一套jetpack框架用于快速实现MVVM(LiveData、Databinding、ViewModel),其中里面为我们处理了很多生命周期相关的重复性工作,消除了大量的重复代码
    • AAC框架里面的核心我认为是Lifecycle,以Activity为例,是通过注入一个无UI的fragment,获取到生命周期的事件,再在里面维护了一个状态机,而且LiveData、ViewModel等的生命周期感知能力都是通过Lifecycle维护的这个状态去控制的
  • 相关阅读:
    web前端期末大作业实例 (1500套) 集合
    docker容器化技术
    小程序内容管理系统设计
    OpenHarmony docker环境搭建
    如何在Vue项目中,通过点击DOM自动定位VScode中的代码行?
    中概股回暖,B站打开向上通道
    【javaEE】网络初识
    【目标检测】Generalized Focal Loss V1
    [阶段4 企业开发进阶] 2. Redis--实战篇
    反射技巧让你的性能提升N倍
  • 原文地址:https://blog.csdn.net/weixin_41802023/article/details/126019400