JetPack浅析

216 阅读6分钟

1. Jetpack是什么?

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

Jectpack组件可分为以下四类:

16df962a96cd78ec~tplv-t2oaga2asx-watermark.image.png

下面主要分享Architecture架构组件:

  • Lifecycle

    构建生命周期感知型组件,这些组件可以根据 Activity 或 Fragment 的当前生命周期状态调整行为。

  • LiveData

    是一种可观察的数据,构建数据对象,在基础数据改变时通知视图。

  • DataBinding

    使用声明性格式,将布局中的界面组件绑定到应用中的数据源,实现数据UI双向绑定。

  • ViewModel

    存储界面相关的数据,这些数据不会在应用旋转时销毁,是一种数据容器。

  • Room

    创建、存储和管理由 SQLite 数据库支持的持久性数据。

  • Paging

    页面中加载数据,在 RecyclerView 中呈现,数据较多时,一种分页组件。

  • Navagation

    构建和组织应用内界面,处理深层链接以及在屏幕之间导航,主要用于Activity和Fragment之间导航。

  • Workmanager

    管理项目中常见的任务。

谷歌官方推荐的Android应用架构如下图所示:

16df962a7ff85640~tplv-t2oaga2asx-watermark.image.png

这些架构组件既可以配合使用,也可以单独使用。

2. Lifecycle

2.1 Lifecyle使用流程

Activity/Fragment作为被观察者,实现LifecycleOwer接口,观察者UserClass实现LifecycleObserver接口,实现与生命周期相关的方法。被观察者中通过调用getLifecycle().addObserver(userCalss);完成订阅关系。当被观察者生命周期发生变化时,会调用观察者中实现的LifecycleObserver的对应方法。

lifecycle2.png

2.2 Lifecyle原理

Lifecycle原理分两步来理解:注册观察者、激活观察者

2.2.1 注册观察者

在LifecycleRegister类的addObserver方法,生成了一个ObserverWithState对象,然后放入FastSafeIterableMap中,其中ObserverWithState包含观察者实现的LifecycleObserver中的方法和对应方法的反射对象。

时序图

addObserver时序图.png

以下为比较关键的源码:

LifecycleRegister.java

@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    //生命周期的状态
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    .......
}

ClassesInfoCache.java

private CallbackInfo createInfo(Class klass, @Nullable Method[] declaredMethods) {
     .......
     //获取LifecycleObserver中所有的方法
    Method[] methods = declaredMethods != null ? declaredMethods : getDeclaredMethods(klass);
    boolean hasLifecycleMethods = false;
    for (Method method : methods) {
        OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
        if (annotation == null) {
            continue;
        }
        ......
        //获取注解的值
        Lifecycle.Event event = annotation.value();

        ......
        //调用类型和方法包装成Method引用
        MethodReference methodReference = new MethodReference(callType, method);
        verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
    }
    CallbackInfo info = new CallbackInfo(handlerToEvent);
    mCallbackMap.put(klass, info);
    mHasLifecycleMethods.put(klass, hasLifecycleMethods);
    return info;
}


private void verifyAndPutHandler(Map<MethodReference, Lifecycle.Event> handlers,
        MethodReference newHandler, Lifecycle.Event newEvent, Class klass) {
    Lifecycle.Event event = handlers.get(newHandler);
    if (event != null && newEvent != event) {
        Method method = newHandler.mMethod;
        throw new IllegalArgumentException(
                "Method " + method.getName() + " in " + klass.getName()
                        + " already declared with different @OnLifecycleEvent value: previous"
                        + " value " + event + ", new value " + newEvent);
    }
    if (event == null) {
        //注解方法引用、注解值存到map中
        handlers.put(newHandler, newEvent);
    }
}

2.2.2 激活观察者

AppCompatActivity 实现了LifecycleOwner接口,同时持有实现了Lifecycle的LifecycleRegistry,这个对象就可以将其理解为观察者模式中的Observable,LifecycleRegistr聚合多个LifecycleObserver,生命周期改变时通知LifecycleObserver进行相应的方法调用。

时序图

观察者激活时序图.png

以下为关键源码:

ComponentActivity.java

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mSavedStateRegistryController.performRestore(savedInstanceState);
    //在当前的Activity里添加一个ReportFragment(无UI的fragment)
    ReportFragment.injectIfNeededIn(this);
    if (mContentLayoutId != 0) {
        setContentView(mContentLayoutId);
    }
}

ReportFragment.java ReportFragment的生命周期函数,都调用了dispatch()方法。

图片.png

dispatch()方法则会判断Activity是否实现了LifecycleOwner接口,如果实现了该接口就调用LifecycleRegister的handleLifecycleEvent() 这样生命周期的状态就会借由LifecycleRegistry通知给各个LifecycleObserver从而调用其中对应Lifecycle.Event的方法。

private void dispatch(Lifecycle.Event event) {
    Activity activity = getActivity();
    if (activity instanceof LifecycleRegistryOwner) {
        ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
        return;
    }
    //是否实现了LifecycleOwner接口
    if (activity instanceof LifecycleOwner) {
        Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
            ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
        }
    }
}

LifecycleRegistry.java

public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    //获取当前activity应该出现的下一个状态
    State next = getStateAfter(event);
    moveToState(next);
}

获取下一个状态的逻辑可根据下图分析: 图片.png


private void moveToState(State next) {
    if (mState == next) {
        return;
    }
    //更新现在的状态
    mState = next;
    if (mHandlingEvent || mAddingObserverCounter != 0) {
        mNewEventOccurred = true;
        // we will figure out what to do on upper level.
        return;
    }
    mHandlingEvent = true;
    sync();
    mHandlingEvent = false;
}

图片.png

private void forwardPass(LifecycleOwner lifecycleOwner) {
    //获取addObserver时存储的类缓存
    Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    while (ascendingIterator.hasNext() && !mNewEventOccurred) {
        Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            pushParentState(observer.mState);
            //时事件分发
            observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState));
            popParentState();
        }
    }
}

图片.png

3. LiveData

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

livadata.png

3.1 基本使用

  1. 定义观察者用以观察livedata中的数据变化。
  2. livedata订阅observer。
  3. livedata发送消息通知observer更新数据,通过回调observer中的onChanged方法实现。 livedata发送消息有两种方式:
    • setValue:只能在主线程运行
    • postValue:只能在子线程中运行

一般一个项目中会有很多个LiveData,我们可以把多个LiveData注册到一条总线上,形成LivaDataBus。Activity负责注册liveData到总线上,观察者订阅总线上的数据变化。

livadatabus.png

3.2 LiveDate原理

可从liveData订阅observe做为入口,了解其原理。

3.2.1 绑定

LiveDate.java

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    //只订阅状态为可见的owner(Activity/Fragment)
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    //包装被观察者和观察者
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
    if (existing != null && !existing.isAttachedTo(owner)) {
        throw new IllegalArgumentException("Cannot add the same observer"
                + " with different lifecycles");
    }
    if (existing != null) {
        return;
    }
    //绑定被观察者和观察者
    owner.getLifecycle().addObserver(wrapper);
}

3.2.2 通知数据变化

绑定完成后,使用setValue与postValue通知观察者。

livadata流程.png

4. DataBinding

使用声明性格式,将布局中的界面组件绑定到应用中的数据源,实现数据UI双向绑定。

4.1 基本使用

  1. gradle文件中启用dataBinding

    dataBinding{
        enabled true
    }
    
  2. 布局文件:

    • 添加layout标签

    • 使用data标签定义数据源

      <data><!--这里面就用来定义数据源-->
          <variable
              name="user"
              type= "com.example.databindingdemo.User"/>
      </data>
      
    • 通过'@{XXX}',设置界面中的组件对应数据

  3. Activity:

    • 获取binding对象
      binding= DataBindingUtil.setContentView(this,R.layout.activity_main);
      
    • 设置数据
      binding.setUser(user);
      

4.2 dataBinding原理

从使用角度入手,分析其原理:

  1. 初始化UI:DatabindingUtil.setContentview
  2. 设置数据:binding.setData

4.2.1 初始化UI

DatabindingUtil.setContentview做的主要事情是,加载布局文,解析XML文件,把布局文件信息保存到 ViewDataBinding对象中。

加载布局文件时,是不能加载data标签的,所以dataBinding把布局文件分成两个文件:

微信截图_20211116233809.png

  • layout-xml文件:

xml-layout.png

  • xml文件

xml.png

  • 获取ViewDataBinding时序图:

setContentView.png

4.2.2 设置数据

public void setUser(@Nullable com.example.databindingdemo.User User) {
    //1.注册监听器更新观查者模式发通知需要相关的信息
    updateRegistration(0, User);
    this.mUser = User;
    synchronized(this) {
        mDirtyFlags |= 0x1L;
    }
    //2.通知数据变化,更新UI
    notifyPropertyChanged(BR.user);
    super.requestRebind();
}

设置数据的过程分为两步:

  1. 注册监听器

    注册监听器.png

  2. 更新UI

通知UI更新.png

5. ViewModel

ViewModel的使用,前面已做简单介绍。

  1. 管理数据,把VIEW中的数据独出来,单独进行管理
  2. 数据的保存与恢复,比如屏幕转动,用户点回退按钮,或切换语言等操作
  3. 主要和LiveData与Room组合使用 注意:ViewModel只是用来管理UI的数据的,不能持有View、Activity或者Fragment的引用(小心内存泄露)。

5.1 获取ViewModel流程:

model = ViewModelProviders.of(this).get(NameViewModel.class)

  1. ViewModelProviders.of(this)

    创建ViewModelStore,ViewModelStore数据结构:HashMap<String, ViewModel>,和Factory,并返回ViewModelProvider。

  2. ViewModelProvider.get(NameViewModel.class)

    保存ViewModel对象到ViewModelStore,并返回ViewModel对象。

获取iewmodel.png

5.2 ViewModel存取流程

屏幕旋转时,AMS通过Binder机制 Activity旋转时,通过调用onRetainCustomNonConfigurationInstance,保存ViewModel,调用getLastNonConfigurationInstance获取缓存的ViewModel。

保存viewmodel.png

6. Room

7. Navagation

8. Workmanager

9. JetPack Demo

github.com/android/sun…

JetPack 的 ViewModel 与MVVM 的 VM的区别

Jetpack中的ViewModel是一个框架,它的职责边界是做状态管理,通过配合LiveData或者DataBinding可以解决与View层的双向依赖,根本上避免了内存泄漏,同时在单Activity中可以实现fragment之间通信,总的来说就是功能很强大。而MVVM是一种架构思想,所以关于它里面的ViewModel层也是一种思想。虽然Jetpack ViewModel可以当作MVVM中的ViewModel,但这只是Jetpack ViewModel可以实现的功能之一,所以俩不能划等号。

github.com/zskingking/…