可被感知的数据 - LiveData 原理详解

前言

在了解LiveData并学习其原理之前,需要先知道Lifecycle的使用以及原理,否则下文某些部分可能较难理解。

传送门-Lifecycle

约定

Observer : 下文无特殊说明都称为观察者
LifecycleOwner: 下文无物特殊说明均称owner(被观察者——具有生命周期)

LiveData是什么

引用源码对于LiveData的注释,个人感觉解释得很到位

/**
 * LiveData is a data holder class that can be observed within a given lifecycle.
 * This means that an {@link Observer} can be added in a pair with a {@link LifecycleOwner}, and
 * this observer will be notified about modifications of the wrapped data only if the paired
 * LifecycleOwner is in active state. LifecycleOwner is considered as active, if its state is
 */

语意大致如下:
        LiveData所持有数据可被感知。在LiveData里,观察者与owner成对出现(当然有例外,后面再说)。在LiveData所持有包装过的数据有变化时,观察者处于active状态时回得到通知。
owner状态处于State.STARTED或State.RESUME时观察者被认为是active状态。

简单来说,LiveData作为一种媒介去持有数据,在数据发生改变时,去通知监测owner并处于active状态的观察者作出应对。

案例

public class MyData extends LiveData<String> {

    private static final String TAG = "T-MyData";

    public  MyData(){
        setValue("hi");
    }

    @Override
    protected void onActive() {
        super.onActive();
        Log.d(TAG, "onActive ");
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        Log.d(TAG, "onInactive ");
    }

    public void changeValue(String value){
        setValue(value);
    }

}
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "T-MainActivity";

    MyData data = new MyData();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                data.changeValue(data.getValue() + "~");
            }
        });
        
        data.observe(this, new Observer<String>() {
            @Override
            public void onChanged(@Nullable String value) {
                Log.d(TAG, "onChanged: " + value );
            }
        });

    }

}

案例行为:LiveData持有String数据,并在MainActivity(也就是owner)生命周期内,观察者对观察其数据。String初始为“hi”,每点击页面上的按钮String在原有拼接上“~”。在数据改变时,onChanged()可接受到改变的数据。 在点击三次案后让MainActiviy进入不可见状态
日志如下


LiveData日志.jpg

从日志上看数据已被感知,此外触发了onActive()以及onInactive() , 二者在什么时候会被触发,下文会有说明。

原理

重要函数

对于使用LiveData重要且包含需要注意事项,挑出以预警

  • setValue()
    protected void setValue(T value) {
        assertMainThread("setValue");
        .....
    }

此函数设置LiveData里的数据,并且执行在主线程里

  • postValue()
    protected void postValue(T value) {
        .....
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

与setValue功能相同,可执行在非主线程
-getValue() : 获取LiveData里的数据,但不保证一定接收到最新数据(比如在异步线程里更新数据被耽误了)

注册过程

前文所述,onwer与观察者称对出现。可通过observe注册。此外,也可通过observeForever进行注册,与observer会有差异。此处针对observe方式先做阐述,observeForver在后文再做比对。

  • LiveData.obsever()
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
        // owner处于Destroy状态已无注册必要
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        // 将owner与观察者进行绑定
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // 一个观察者仅仅针对一个onwer
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        // 这里的getLifecycle一般是Lifecycle里说的LifecycleRegistry
        owner.getLifecycle().addObserver(wrapper);
    }

从代码上看,注册时,先排查owner状态是否合适,紧接着将owner与观察者进行了绑定,且从抛出的异常可以知道,owner与观察者的关系为一对多。此后将包装好的ObserverWrapper交给LifecycleRegistry,这样,就确保了再State.Event事件到达时,ObserverWrapper会接受到讯息。 (Lifecycle知识,忘了去这里->传送门

绑定过程

   class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
        @NonNull final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
            super(observer);
            mOwner = owner;
        }
      
      .....
}
 private abstract class ObserverWrapper {
        final Observer<T> mObserver;

        ObserverWrapper(Observer<T> observer) {
            mObserver = observer;
        }
    ......
    }

这里贴出了LifecycleBoundObserver与其父类ObserverWrapper的部分内容,可见两者分别持有了owner与观察者信息。

到这里,整个注册过程完毕。过程很简单,做个小结

  • 绑定owner与观察者,信息收集入LifecycleBoundObserver
  • 将LifecycleBoundObserver交接给LifecycleRegistry进行注册,以便Event事件到来时得以接收

感知过程

在Lifecycle知识里知道,Event最终会经过GenericLifecycleObserver的实现类作为中转者经过处理,传达到具体的观察者。从之前的代码截图可以知道LifecycleBoundObserver是GenericLifecycleObserver的实现类,因此能接收到Event事件。

public interface GenericLifecycleObserver extends LifecycleObserver {
    void onStateChanged(LifecycleOwner source, Lifecycle.Event event);
}

GenericLifecycleObserver对于Lifecycle的体系来说,是个观察者(针对Lifecycle),与实际的观察者(针对Lifecycle),两种是职责上的区别,因此,职责是可以同时抗在肩上的。
回顾一下Lifecycle的原理,代码位置如下

当前位置
- LifecycleRegistry.addObserver()
-- ObserverWithState()
--- Lifecycling.getCallback()
static GenericLifecycleObserver getCallback(Object object) {
       .....
        if (object instanceof GenericLifecycleObserver) {
            return (GenericLifecycleObserver) object;
        }
      .....
    }

可见,如果观察者(针对Lifecycle)是GenericLifecycleObserver的话,Event事件是由观察者(针对Lifecycle)自行处理的,此类观察者包揽了以上所述职责。(可以查看Lifecycle体系里的SingleGeneratedAdapterObserver会一目了然,如果都忘了传送门,对于理解很重要)。

当前位置
- LifecycleBoundObserver.onStateChanged()

        @Override
        public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
            // 检查owner状态
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                // 已销毁移除,避免内存泄漏
                removeObserver(mObserver);
                return;
            }
            // 检测观察者是否处于active状态,并作出相应对策
            activeStateChanged(shouldBeActive());
        }
}


当前位置
- LifecycleBoundObserver. shouldBeActive()
        @Override
        boolean shouldBeActive() {
            // true标示owner至少处于State.STARTED状态
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

不解释

当前位置
- LifecycleBoundObserver. activeStateChanged()
        void activeStateChanged(boolean newActive) {
            // 同一状态下不做处理
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            // 更新状态
            mActive = newActive;
            // 是否有处于active状态的观察者
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
             1⃣️
            if (wasInactive && mActive) {
                onActive();
            }
            2⃣️
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            // 通知数据情况
            if (mActive) {
                dispatchingValue(this);
            }
        }

1和2标注部分是指,owner处于State.STARTED、State.RESUMED时观察者为active状态,而State.INITIALIZED、State.CREATED为inActive状态,因此,同种状态下仅做单次回调。

数据通知

当前位置
LifecycleBoundObserver. dispatchingValue()

    private void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;
            return;
        }
        mDispatchingValue = true;
        do {
            mDispatchInvalidated = false;
            if (initiator != null) {
                // 尝试通知观察者
                considerNotify(initiator);
                initiator = null;
            } else {
                for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    // 尝试通知观察者
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false;
    }

这里仅需知道dispatchingValue()会根据观察者的不同,都会尝试通知观察者。

当前位置
- LifecycleBoundObserver. dispatchingValue()
-- considerNotify()

    private void considerNotify(ObserverWrapper observer) {
        // 观察者处于inActive状态
        if (!observer.mActive) {
            return;
        }
       // 源码注释为,检查观察者是否响应此次更改的意义在于,虽然观察者可能
      // 处于响应的状态,但此时并没有接收到明确的Event通知,最好不要通知以
      // 保持良好的通知秩序
      
      //  这里可以理解为,防止素乱而引起的可能的内存泄漏的问题,也为了保证
      //  同一状态下仅做单次通知
        if (!observer.shouldBeActive()) {
            //  这里回到了触发considerNotify的起点,是为了等待,修复素乱
            observer.activeStateChanged(false);
            return;
        }
      // 数据没有更改不做通知
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        // 观察者回调
        observer.mObserver.onChanged((T) mData);
    }

除了代码中注释处的解释,还要知道的信息是,LiveData拥有私有变量mVersion对持有数据版本做了维护,只有检测到版本更新时才做通知。

此外,在setValue()是也能触发considerNotify()

    protected void setValue(T value) {
        // 在主线程执行
        assertMainThread("setValue");
        // 数据版本更新
        mVersion++;
        mData = value;
        // 通知
        dispatchingValue(null);
    }

分发过程结束,小结如下:

  • ObserverWrapper与子类负责持有owner与观察者信息,并实现GenericLifecycleObserver自行处理Event事件
  • Event事件到达时,根据owner的State做LiveData做相应处理,在观察者处于active状态时,回调onActive(); 在处于inActive时回调onInactive()
  • owner生命周期转变时或更新数据时,LiveData向处于active状态的观察者进行通知

提醒

文章到这里还没有结束,对于LiveData而言,注册防止不仅提供了observe的注册方式,还提供了observeForever的注册方式

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
public void observeForever(@NonNull Observer<T> observer) 

仅从参数上来看,很容易想到观察者并没有针对指定的onwer进行绑定,从之前的分析来看,在onwer销毁时,观察者也会一并被销毁,因此,此处能联想到,较之Observe的注册方式,observeForever会注册的观察者自身会拥有更广阔的生命周期。

  • Adds the given observer to the observers list. This call is similar to * {@link LiveData#observe(LifecycleOwner, Observer)} with a LifecycleOwner, which is always active. This means that the given observer will receive all events and will never be automatically removed. You should manually call {@link#removeObserver(Observer)} to stop observing this LiveData.

摘自源码对于observeForever的注释,大意如下:
此方法与observe相似,但是观察者总会收到事件并且不会被自动移除,需要手动移除。

可见,在使用上以及原理处需要做甄别。

案例

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "T-MainActivity";

    MyData data = BActivity.data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.text).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                data.changeValue(data.getValue() + "~");
            }
        });

        findViewById(R.id.startBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, BActivity.class);
                startActivity(intent);
            }
        });

    }

}

public class BActivity extends AppCompatActivity {

    private static final String TAG = "T-BActivity";

    public static MyData data = new MyData();
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);
        data.observeForever(new Observer<String>() {
            @Override
            public void onChanged(@Nullable String value) {
                Log.d(TAG, "I'am still here , value is : " + value);
            }
        });
    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        finish();
    }
}

页面描述:在B页面有LiveData的静态对象,在按下返回键时B会被销毁。Main页面有Click Me按钮,点击时LiveData的数据加上"~"拼接,并有另一个按钮以启动B页面。
页面操作:从Main启动B,按下返回键,多次点击Click Me按钮,日志如下


日志2.jpg

容易证实,观察者依旧存在。

observeForever原理

    public void observeForever(@NonNull Observer<T> observer) {
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // 除了和observe()类似的检测外,还不能是LifecycleBoundObserver类
        if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

代码上看,流程是类似的,不过observeForever()并不能使用observe()使用的LifecycleBoundObserver,并且没有通过Lifecycle.LifecycleRegistry进行注册,能猜测通过此方式注册的观察者,并没有和实际的owner进行绑定(之前所说的没有成对出现的情况)。答案会在AlwaysActiveObserver里找到

    private class AlwaysActiveObserver extends ObserverWrapper {

        AlwaysActiveObserver(Observer<T> observer) {
            super(observer);
        }

        @Override
        boolean shouldBeActive() {
            return true;
        }
    }

AlwaysActiveObserver很简单,仅有shouldBeActive()方法 ,并且结合之前所述的通过Observe()注册,能知道通过observeForever()注册的观察者性质如下:

  • 并没有利用Lifycycle的机制,所以没有对生命周期的感知
  • 行为就是简单的观察者模式的简单监听与回调
  • 有内存泄漏风险,记得手动移除

简单原理图

LiveData原理图-2.png

图片除了注册过程以及感知过程外,还画出了接收过程,因为理解Lifecycle原理真的对理解很重要

提示

文章到这里就结束了,以下部分为小插曲,感兴趣欢迎阅读

插曲

LiveData的优势在于让数据感知生命周期的变化以及实现数据的共享。在学习LiveData的过程中,有查阅过一些相应的博文,其中让我很关注的地方是,有些地方指出,使用单例让LiveData实现数据共享,并对此不再做必要的解释,很容易引起混淆和误解。
单例只是无可奈何之下的一种形式,是最差解。
LiveData的数据共享的精髓在于利用观察者,而不是利用过长的生命周期。并且,LiveData所要解决的问题是,具有生命周期的组件如何在自身的生命周期里根据必要性的或者重要性的数据状态,来调整自身的状态,并实现生命周期监测与数据状态的解耦。

笔者的呢喃:我都单例了,我都自我共享了,我还需要感知 0 0?

(笔者在🌰中使用了静态对象LiveData仅仅是为了方便展示,实际运用中不要这么干)


在此感谢涂哥的指导和答疑


下一篇:ViewModel

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

推荐阅读更多精彩内容