Jetpack(一)Lifecycle和LiveData

源码分析:JetPacks之Lifecycles原理
应用:JetPacks之数据传递工具
联系:JetPack之 LifeCycle LiveData

Lifecycle

  • Lifecycle可以有效的避免内存泄漏和解决android生命周期的常见难题
  • Lifecycle 是一个表示android生命周期及状态的对象
  • LivecycleOwner 用于连接有生命周期的对象,如activity,fragment
  • LivecycleObserver 用于观察查LifecycleOwner

基本使用

Lifecycle框架使用观察者模式实现观察者监听被观察者的生命周期的变化

定义被观察者>>

通过实现LifecycleOwner接口

ComponentActivity.png

如上图:我们使用activity不需要再自己写实现接口的代码

定义观察者>>

通过实现LifecycleObserver接口

BasePresenter.png

通过注解在观察者类中定义需要监听的生命周期

注:以下方法都会在被观察者生命周期变化时调用
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    void onCreateX(LifecycleOwner owner) {

    }


    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStartX(LifecycleOwner owner) {
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop(LifecycleOwner owner) {
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void onResume(LifecycleOwner owner) {
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    void onPause(LifecycleOwner owner) {
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestory(LifecycleOwner owner) {
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    void onAny(LifecycleOwner owner) {
    }

完成订阅关系>>

在activity中使用

被观察者.addObserver(观察者)
getLifecycle().addObserver(presenter);

环境配置>>

自己引入
dependencies {
  implementation "androidx.lifecycle:lifecycle-runtime:2.0.0"
  implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
  implementation "androidx.lifecycle:lifecycle-common-java8:2.0.0"
  annotationProcessor  "androidx.lifecycle:lifecycle-compiler:2.0.0"
}

核心原理

LifecycleRegister#addObserver

看一下LifecycleRegister 类中的addObserver方法这里你会发现生成了一个ObserverWithState,然后放入FastSafeIterableMap里,这个类是一个自定义列表,用于保存观察者并可在遍历期间处理删除/添加。

  1. AppCompatActivity

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

  1. ReportFragment Commponent#ReportFragment.injectIfNeededIn

AppCompatActivity 继承的extends androidx.core.app.ComponentActivity中的onCretae方法ReportFragment.injectIfNeededIn(this);
就是在当前的Activity里添加一个ReportFragment。

  1. ReportFragment#dispatch()

再看ReportFragment的生命周期函数
你会发现都调用了dispatch()方法,

  1. LifecycleRegistry#handleLifecycleEvent

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

  1. handleLifecycleEvent--->getStateAfter

回到handleLifecycleEvent方法中
State next = getStateAfter(event);
事件发生的时候,先得到当前activity应该出现的下一个状态

  1. 状态机流转

moveToState(next);
mState = next;更新现在的状态
sync();
backwardPass(lifecycleOwner);逆推
forwardPass(lifecycleOwner);

state.png
  1. forwardPass(lifecycleOwner)

forwardPass(lifecycleOwner)方法中的细节
ObserverWithState observer = entry.getValue();
找到ObserverWithState 类
调用mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
生成观察者适配器

  1. onStateChanged

接下来就是调用onStateChanged(),来通知 实现了 LifecycleObserver的类,生命周期发生了变化

  1. ReflectiveGenericLifecycleObserver

查看实现类
ReflectiveGenericLifecycleObserver。onStateChanged()

ReflectiveGenericLifecycleObserver。的构造方法中就把presenter中的方法和注解保存了下来
再通过onStateChanged()进行生命周期的方法的调用

源码分析 JetPacks之Lifecycles原理

应用 JetPacks之数据传递工具

Demo JetPack之 LifeCycle LiveData

LiveData

LiveData是一种具有生命周期感知能力的可观察数据持有类
LiveData可以保证屏幕上的显示内容和数据一直保持同步
特点:
1.LiveData了解UI界面的状态,如果activity不在屏幕上显示,livedata不会触发没必要的界面更新,如果activity已经被销毁,会自动清空与observer的连接,意外的调用就不会发生
2.LiveData是一个LifecycleOwner,他可以直接感知activity或fragment的生命周期

基本使用

定义LifeData >>

项目中livedata一般都存放在ViewModel中,以保证app配置变更时,数据不会丢失

举个例子:

public class NameViewModel extends ViewModel {
    public int i = 0;
    private MutableLiveData<String> currentName;
    public MutableLiveData<String> getCurrentName(){
        if(currentName==null){
            currentName=new MutableLiveData<>();
        }
        return currentName;
    }
}

使用流程 >>

定义观察者用以观察livedata中的数据变化

//需要一个观察者来观察数据
        Observer observer=new Observer<String>(){
            @Override
            public void onChanged(String s) {
                nameTextView.setText(s);
            }
        };

livedata订阅observer

        //获取到viewmodel
        model= ViewModelProviders.of(this).get(NameViewModel.class);
        //取出livedata完成订阅
        model.getCurrentName().observe(this,observer);

livedata发送消息通知observer更新数据

model.getCurrentName().setValue(anotherName);
以上代码会回调observer中的onChanged方法

使用注意:

setValue只能在主线程运行

postValue只能在子线程中运行

核心原理

1.observe做为入口>>

使用LifecycleBoundObserver把观察者和被观察者包装在一起
绑定wrapper作为观察者

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

  1. setValue中 >>

-------dispatchingValue(null)
if (initiator != null)
参数传null和不传null的区别就是如果传null将会通知所有的观察者,反之仅仅通知传入的观察者。
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
通知所有的观察者通过遍历 mObservers ,将所有的 ObserverWrapper 拿到,实际上就是我们上面提到的 LifecycleBoundObserver,通知观察者调用considerNotify()方法,这个方法就是通知的具体实现了。

-------considerNotify()

先用2个if判断出被观察者对应的activity状态是否为显示
发送通知 onChanged()被调用

  1. postValue中 >>

切换线程到主线程中去执行setValue

LiveDataEventBus

通过一个集合统一管理所有的LiveData
设计中的BUG:
原来的执行顺序new LiveData-->绑定observer-->setValue执行onChanged
而我们的BUS在用时可能出现 new LiveData-->setValue执行onChanged-->绑定observer
处理方案,让第一次setValue不起效即可

参考Github

LiveDataBus

package top.zcwfeng.jetpack.utils;

import androidx.lifecycle.MutableLiveData;

import java.util.HashMap;
import java.util.Map;

public class LiveDataBus {
    //存放订阅者
    private Map<String, MutableLiveData<Object>> bus;
    private static LiveDataBus liveDataBus = new LiveDataBus();

    private LiveDataBus() {
        bus = new HashMap();
    }
    public static LiveDataBus getInstance() {
        return liveDataBus;
    }
    //注册订阅者
    public synchronized <T> MutableLiveData<T> with(String key, Class<T> type) {
        if(!bus.containsKey(key)){
            bus.put(key,new MutableLiveData<Object>());
        }
        return (MutableLiveData<T>)bus.get(key);
    }
}

LiveDataXBus 解除 LiveDataBus 粘性问题,某些场景需要

/**
 * 解除 LiveDataBus 粘性问题,某些场景需要
 */
public class LiveDataBusX {
    //存放订阅者
    private Map<String, BusMutableLiveData<Object>> bus;

    private static LiveDataBusX liveDataBus = new LiveDataBusX();

    private LiveDataBusX() {
        bus = new HashMap<>();
    }

    public static LiveDataBusX getInstance() {
        return liveDataBus;
    }

    //注册订阅者,(存入map) Hook前用MutableLiveData
    public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type){
        if(!bus.containsKey(key)){
            bus.put(key,new BusMutableLiveData<Object>());
        }
        return (BusMutableLiveData<T>) bus.get(key);
    }

    public static class BusMutableLiveData<T> extends MutableLiveData<T> {
        @Override
        public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
            super.observe(owner, observer);
            hook(observer);
        }
        //在这里去改变onChange的流程
        private void hook(Observer<? super T> observer) {
            try {
                //1.得到mLastVersion
                //获取到LiveData的类中的mObservers对象
                Class<LiveData> liveDataClass = LiveData.class;
                Field mObserversField = liveDataClass.getDeclaredField("mObservers");
                mObserversField.setAccessible(true);
                //获取到这个成员变量的对象
                Object mObserversObject = mObserversField.get(this);
                //得到map对应的class对象
                Class<?> mObserversClass = mObserversObject.getClass();
                //获取到mObservers对象的get方法
                Method get = mObserversClass.getDeclaredMethod("get", Object.class);
                get.setAccessible(true);
                //执行get方法
                Object invokeEntry=get.invoke(mObserversObject,observer);
                //定义一个空的对象
                Object observerWraper=null;
                if(invokeEntry!=null && invokeEntry instanceof Map.Entry){
                    observerWraper=((Map.Entry)invokeEntry).getValue();
                }
                if(observerWraper==null){
                    throw new NullPointerException("observerWraper is null");
                }
                //得到ObserverWrapper的类对象  编译擦除问题会引起多态冲突所以用getSuperclass
                Class<?> superclass = observerWraper.getClass().getSuperclass();
                Field mLastVersion = superclass.getDeclaredField("mLastVersion");
                mLastVersion.setAccessible(true);
                //2.得到mVersion
                Field mVersion = liveDataClass.getDeclaredField("mVersion");
                mVersion.setAccessible(true);
                //3.把mVersion的数据填入到mLastVersion中
                Object mVersionValue=mVersion.get(this);
                mLastVersion.set(observerWraper,mVersionValue);


            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

}

目录:

Jetpack(一)Lifecycle和LiveData
JetPacks之Lifecycles原理
JetPack之 LifeCycle LiveData

Jetpack(二)之DataBinding

Jetpack(三) 之 Room 与 ViewModel
Jetpack 之 ViewModel 原理

Jetpack (四) 之 Navigation
Jetpack Navigation 原理浅析

JetPack (五)之 Paging 分页库

Jetpack(六) 之 WorkManager
Jetpack WorkManager 原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 在《也谈Android应用架构》中我们对MVC、MVP、MVVM进行了详尽的分析,但还有一个问题悬而未决,那就是生...
    大大纸飞机阅读 949评论 0 6
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,475评论 16 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,548评论 0 11
  • 可爱进取,孤独成精。努力飞翔,天堂翱翔。战争美好,孤独进取。胆大飞翔,成就辉煌。努力进取,遥望,和谐家园。可爱游走...
    赵原野阅读 2,713评论 1 1
  • 在妖界我有个名头叫胡百晓,无论是何事,只要找到胡百晓即可有解决的办法。因为是只狐狸大家以讹传讹叫我“倾城百晓”,...
    猫九0110阅读 3,255评论 7 3