“終于懂了“系列:Jetpack AAC完整解析(二)LiveData 完全掌握慎王!

Jetpack AAC 系列文章:

“終于懂了“系列:Jetpack AAC完整解析(-)Lifecycle 完全掌握组哩!

“終于懂了“系列:Jetpack AAC完整解析(二)LiveData 完全掌握特漩!

“終于懂了“系列:Jetpack AAC完整解析(三)ViewModel 完全掌握纤怒!

“終于懂了“系列:Jetpack AAC完整解析(四)MVVM - Android架構探索黄娘!

“終于懂了“系列:Jetpack AAC完整解析(五)DataBinding 重新認知峭状!

上一篇介紹了Jetpack AAC 的基礎組件 Lifecycle,它是用于管理Activity/Fragment的生命周期逼争。這篇來介紹基于Lifecycle的用于處理數(shù)據(jù)的組件——LiveData优床。

一、LiveData介紹

1.1 作用

LiveData是Jetpack AAC的重要組件誓焦,同時也有一個同名抽象類胆敞。

LiveData,原意是 活著的數(shù)據(jù)杂伟。 數(shù)據(jù)還能有生命移层? 先來看下官方的定義:

LiveData 是一種可觀察的數(shù)據(jù)存儲器類。與常規(guī)的可觀察類不同赫粥,LiveData 具有生命周期感知能力观话,意指它遵循其他應用組件(如 Activity/Fragment)的生命周期。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態(tài)的應用組件觀察者越平。

拆解開來:

  1. LiveData是一個數(shù)據(jù)持有者频蛔,給源數(shù)據(jù)包裝一層。
  2. 源數(shù)據(jù)使用LiveData包裝后秦叛,可以被observer觀察晦溪,數(shù)據(jù)有更新時observer可感知。
  3. 但 observer的感知挣跋,只發(fā)生在(Activity/Fragment)活躍生命周期狀態(tài)(STARTED三圆、RESUMED)。

也就是說,LiveData使得 數(shù)據(jù)的更新 能以觀察者模式 被observer感知嫌术,且此感知只發(fā)生在 LifecycleOwner的活躍生命周期狀態(tài)哀澈。

1.2 特點

使用 LiveData 具有以下優(yōu)勢:

  • 確保界面符合數(shù)據(jù)狀態(tài),當生命周期狀態(tài)變化時度气,LiveData通知Observer割按,可以在observer中更新界面。觀察者可以在生命周期狀態(tài)更改時刷新界面磷籍,而不是在每次數(shù)據(jù)變化時刷新界面适荣。
  • 不會發(fā)生內存泄漏,observer會在LifecycleOwner狀態(tài)變?yōu)镈ESTROYED后自動remove院领。
  • 不會因 Activity 停止而導致崩潰弛矛,如果LifecycleOwner生命周期處于非活躍狀態(tài),則它不會接收任何 LiveData事件比然。
  • 不需要手動解除觀察丈氓,開發(fā)者不需要在onPause或onDestroy方法中解除對LiveData的觀察,因為LiveData能感知生命周期狀態(tài)變化强法,所以會自動管理所有這些操作万俗。
  • 數(shù)據(jù)始終保持最新狀態(tài),數(shù)據(jù)更新時 若LifecycleOwner為非活躍狀態(tài)饮怯,那么會在變?yōu)榛钴S時接收最新數(shù)據(jù)闰歪。例如,曾經(jīng)在后臺的 Activity 會在返回前臺后蓖墅,observer立即接收最新的數(shù)據(jù)库倘。

二、LiveData的使用

下面介紹LiveData的使用论矾,掌握使用方法也可以更好理解上面的內容教翩。

2.1基本使用

gradle依賴在上一篇中已經(jīng)介紹了。下面來看基本用法:

  1. 創(chuàng)建LiveData實例贪壳,指定源數(shù)據(jù)類型
  2. 創(chuàng)建Observer實例迂曲,實現(xiàn)onChanged()方法,用于接收源數(shù)據(jù)變化并刷新UI
  3. LiveData實例使用observe()方法添加觀察者寥袭,并傳入LifecycleOwner
  4. LiveData實例使用setValue()/postValue()更新源數(shù)據(jù) (子線程要postValue())

舉個例子:

public class LiveDataTestActivity extends AppCompatActivity{

   private MutableLiveData<String> mLiveData;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_lifecycle_test);
       
       //liveData基本使用
       mLiveData = new MutableLiveData<>();
       mLiveData.observe(this, new Observer<String>() {
           @Override
           public void onChanged(String s) {
               Log.i(TAG, "onChanged: "+s);
           }
       });
       Log.i(TAG, "onCreate: ");
       mLiveData.setValue("onCreate");//activity是非活躍狀態(tài)路捧,不會回調onChanged。變?yōu)榛钴S時传黄,value被onStart中的value覆蓋
   }
   @Override
   protected void onStart() {
       super.onStart();
       Log.i(TAG, "onStart: ");
       mLiveData.setValue("onStart");//活躍狀態(tài)杰扫,會回調onChanged。并且value會覆蓋onCreate膘掰、onStop中設置的value
   }
   @Override
   protected void onResume() {
       super.onResume();
       Log.i(TAG, "onResume: ");
       mLiveData.setValue("onResume");//活躍狀態(tài)章姓,回調onChanged
   }
   @Override
   protected void onPause() {
       super.onPause();
       Log.i(TAG, "onPause: ");
       mLiveData.setValue("onPause");//活躍狀態(tài)佳遣,回調onChanged
   }
   @Override
   protected void onStop() {
       super.onStop();
       Log.i(TAG, "onStop: ");
       mLiveData.setValue("onStop");//非活躍狀態(tài),不會回調onChanged凡伊。后面變?yōu)榛钴S時零渐,value被onStart中的value覆蓋
   }
   @Override
   protected void onDestroy() {
       super.onDestroy();
       Log.i(TAG, "onDestroy: ");
       mLiveData.setValue("onDestroy");//非活躍狀態(tài),且此時Observer已被移除系忙,不會回調onChanged
   }
}

注意到 LiveData實例mLiveData的創(chuàng)建是使用MutableLiveData诵盼,它是LiveData的實現(xiàn)類,且指定了源數(shù)據(jù)的類型為String银还。然后創(chuàng)建了接口Observer的實例风宁,實現(xiàn)其onChanged()方法,用于接收源數(shù)據(jù)的變化蛹疯。observer和Activity一起作為參數(shù)調用mLiveData的observe()方法戒财,表示observer開始觀察mLiveData。然后Activity的所有生命周期方法中都調用了mLiveData的setValue()方法捺弦。 結果日志打印如下:

//打開頁面饮寞,
2020-11-22 20:23:29.865 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onCreate: 
2020-11-22 20:23:29.867 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onStart: 
2020-11-22 20:23:29.868 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onStart
2020-11-22 20:23:29.869 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onResume: 
2020-11-22 20:23:29.869 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onResume
//按Home鍵
2020-11-22 20:23:34.349 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onPause: 
2020-11-22 20:23:34.349 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onPause
2020-11-22 20:23:34.368 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onStop: 
//再點開
2020-11-22 20:23:39.145 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onStart: 
2020-11-22 20:23:39.146 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onStart
2020-11-22 20:23:39.147 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onResume: 
2020-11-22 20:23:39.147 13360-13360/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onResume
//返回鍵退出
2020-11-22 20:23:56.753 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onPause: 
2020-11-22 21:23:56.753 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onChanged: onPause
2020-11-22 20:23:58.320 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onStop: 
2020-11-22 20:23:58.322 14432-14432/com.hfy.androidlearning I/Lifecycle_Test: onDestroy: 
  • 首先打開頁面,onCreate()中setValue列吼,由于activity是非活躍狀態(tài)幽崩,不會立即回調onChanged。當走到onStart()變?yōu)榛钴S時冈欢,onChanged被調用,但value被onStart()中setValue的value覆蓋盈简,所以打印的是onChanged: onStart凑耻。(為啥不是連續(xù)打印兩次呢?柠贤,是因為ON_START事件是在onStart() return之后香浩,即onStart()走完之后才變?yōu)榛钴S<詳見上一篇>,此時observer接收最新的數(shù)據(jù)臼勉。) 接著走到onResume()邻吭,也setValue了,同樣是活躍狀態(tài)宴霸,所以立刻回調onChanged囱晴,打印onChanged: onResume

  • 按Home鍵時,onPause()中setValue瓢谢,活躍狀態(tài)畸写,立刻回調onChanged方法管嬉。onStop()執(zhí)行時已經(jīng)變?yōu)榉腔钴S狀態(tài)称杨,此時setValue不會立即回調onChanged方法袭蝗。

  • 再點開時眨八,走到onStart()變?yōu)榛钴S時左电,onChanged被調用廉侧,但value被onStart()中setValue的value覆蓋页响,所以打印的是onChanged: onStart。接著走到onResume()段誊,也setValue了闰蚕,同樣是活躍狀態(tài),所以立刻回調onChanged连舍。

  • 返回鍵退出時没陡,onPause()/onStop()的效果和按Home鍵一樣。onDestroy()中setValue索赏,此時非活躍狀態(tài)盼玄,且此時observer已被移除,不會回調onChanged潜腻。

另外埃儿,除了使用observe()方法添加觀察者,也可以使用observeForever(Observer) 方法來注冊未關聯(lián) LifecycleOwner的觀察者融涣。在這種情況下童番,觀察者會被視為始終處于活躍狀態(tài)。

2.2 擴展使用

擴展包括兩點:

  1. 自定義LiveData威鹿,本身回調方法的覆寫:onActive()剃斧、onInactive()。
  2. 實現(xiàn)LiveData為單例模式忽你,便于在多個Activity幼东、Fragment之間共享數(shù)據(jù)。

官方的例子如下:

public class StockLiveData extends LiveData<BigDecimal> {
        private static StockLiveData sInstance; //單實例
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);//監(jiān)聽到股價變化 使用setValue(price) 告知所有活躍觀察者
            }
        };

    //獲取單例
        @MainThread
        public static StockLiveData get(String symbol) {
            if (sInstance == null) {
                sInstance = new StockLiveData(symbol);
            }
            return sInstance;
        }

        private StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        //活躍的觀察者(LifecycleOwner)數(shù)量從 0 變?yōu)?1 時調用
        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);//開始觀察股價更新
        }

        //活躍的觀察者(LifecycleOwner)數(shù)量從 1 變?yōu)?0 時調用科雳。這不代表沒有觀察者了根蟹,可能是全都不活躍了≌ǘ桑可以使用hasObservers()檢查是否有觀察者娜亿。
        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);//移除股價更新的觀察
        }
    }
    

為了觀察股票價格變動丽已,繼承LiveData自定義了StockLiveData蚌堵,且為單例模式,只能通過get(String symbol)方法獲取實例沛婴。 并且重寫了onActive()吼畏、onInactive(),并加入了 開始觀察股價更新嘁灯、移除股價更新觀察 的邏輯泻蚊。

  • onActive()調用時機為:活躍的觀察者(LifecycleOwner)數(shù)量從 0 變?yōu)?1 時。
  • onInactive()調用時機為:活躍的觀察者(LifecycleOwner)數(shù)量從 1 變?yōu)?0 時丑婿。

也就是說性雄,只有當 存在活躍的觀察者(LifecycleOwner)時 才會連接到 股價更新服務 監(jiān)聽股價變化没卸。使用如下:

    public class MyFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            //獲取StockLiveData單實例,添加觀察者秒旋,更新UI
            StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
                // Update the UI.
            });
        }
    }

由于StockLiveData是單實例模式约计,那么多個LifycycleOwner(Activity、Fragment)間就可以共享數(shù)據(jù)了迁筛。

2.3 高級用法

如果希望在將 LiveData 對象分派給觀察者之前對存儲在其中的值進行更改煤蚌,或者需要根據(jù)另一個實例的值返回不同的 LiveData 實例,可以使用LiveData中提供的Transformations類细卧。

2.3.1 數(shù)據(jù)修改 - Transformations.map

        //Integer類型的liveData1
        MutableLiveData<Integer> liveData1 = new MutableLiveData<>();
        //轉換成String類型的liveDataMap
        LiveData<String> liveDataMap = Transformations.map(liveData1, new Function<Integer, String>() {
            @Override
            public String apply(Integer input) {
                String s = input + " + Transformations.map";
                Log.i(TAG, "apply: " + s);
                return s;
            }
        });
        liveDataMap.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged1: "+s);
            }
        });

        liveData1.setValue(100);

使用很簡單:原本的liveData1 沒有添加觀察者尉桩,而是使用Transformations.map()方法 對liveData1的數(shù)據(jù)進行的修改 生成了新的liveDataMap,liveDataMap添加觀察者贪庙,最后liveData1設置數(shù)據(jù) 蜘犁。

此例子把 Integer類型的liveData1 修改為String類型的liveDataMap。結果如下:

2020-12-06 17:01:56.095 21998-21998/com.hfy.androidlearning I/Lifecycle_Test: apply: 100 + Transformations.map
2020-12-06 17:01:56.095 21998-21998/com.hfy.androidlearning I/Lifecycle_Test: onChanged1: 100 + Transformations.map

2.3.2 數(shù)據(jù)切換 - Transformations.switchMap

如果想要根據(jù)某個值 切換觀察不同LiveData數(shù)據(jù)插勤,則可以使用Transformations.switchMap()方法沽瘦。

    //兩個liveData,由liveDataSwitch決定 返回哪個livaData數(shù)據(jù)
        MutableLiveData<String> liveData3 = new MutableLiveData<>();
        MutableLiveData<String> liveData4 = new MutableLiveData<>();
        
    //切換條件LiveData农尖,liveDataSwitch的value 是切換條件
        MutableLiveData<Boolean> liveDataSwitch = new MutableLiveData<>();
        
    //liveDataSwitchMap由switchMap()方法生成析恋,用于添加觀察者
        LiveData<String> liveDataSwitchMap = Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData<String>>() {
            @Override
            public LiveData<String> apply(Boolean input) {
            //這里是具體切換邏輯:根據(jù)liveDataSwitch的value返回哪個liveData
                if (input) {
                    return liveData3;
                }
                return liveData4;
            }
        });

        liveDataSwitchMap.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged2: " + s);
            }
        });

        boolean switchValue = true;
        liveDataSwitch.setValue(switchValue);//設置切換條件值

        liveData3.setValue("liveData3");
        liveData4.setValue("liveData4");

liveData3、liveData4是兩個數(shù)據(jù)源盛卡,有一個判斷條件來決定 取哪一個數(shù)據(jù) 助隧,這個條件就是liveDataSwitch,如果值為true則取liveData3滑沧,false則取liveData4并村。 Transformations.switchMap()就用于實現(xiàn)這一邏輯,返回值liveDataSwitchMap添加觀察者就可以了滓技。 結果如下:

2020-12-06 17:33:53.844 27347-27347/com.hfy.androidlearning I/Lifecycle_Test: switchValue=true
2020-12-06 17:33:53.847 27347-27347/com.hfy.androidlearning I/Lifecycle_Test: onChanged2: liveData3

2020-12-06 17:34:37.600 27628-27628/com.hfy.androidlearning I/Lifecycle_Test: switchValue=false
2020-12-06 17:34:37.602 27628-27628/com.hfy.androidlearning I/Lifecycle_Test: onChanged2: liveData4

(Transformations對LivaData這兩個用法和Rxjava簡直一毛一樣)

2.3.3 觀察多個數(shù)據(jù) - MediatorLiveData

MediatorLiveData 是 LiveData 的子類哩牍,允許合并多個 LiveData 源。只要任何原始的 LiveData 源對象發(fā)生更改令漂,就會觸發(fā) MediatorLiveData 對象的觀察者膝昆。

        MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();

        MutableLiveData<String> liveData5 = new MutableLiveData<>();
        MutableLiveData<String> liveData6 = new MutableLiveData<>();

    //添加 源 LiveData
        mediatorLiveData.addSource(liveData5, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged3: " + s);
                mediatorLiveData.setValue(s);
            }
        });
    //添加 源 LiveData
        mediatorLiveData.addSource(liveData6, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged4: " + s);
                mediatorLiveData.setValue(s);
            }
        });

    //添加觀察
        mediatorLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged5: "+s);
                //無論liveData5、liveData6更新叠必,都可以接收到
            }
        });
        
        liveData5.setValue("liveData5");
        //liveData6.setValue("liveData6");

例如荚孵,如果界面中有可以從本地數(shù)據(jù)庫或網(wǎng)絡更新的 LiveData 對象,則可以向 MediatorLiveData 對象添加以下源:

  • 與存儲在本地數(shù)據(jù)庫中的數(shù)據(jù)關聯(lián)的 liveData5
  • 與從網(wǎng)絡訪問的數(shù)據(jù)關聯(lián)的 liveData6
    Activity 只需觀察 MediatorLiveData 對象即可從這兩個源接收更新纬朝。
    結果如下:
2020-12-06 17:56:17.870 29226-29226/com.hfy.androidlearning I/Lifecycle_Test: onChanged3: liveData5
2020-12-06 17:56:17.870 29226-29226/com.hfy.androidlearning I/Lifecycle_Test: onChanged5: liveData5

(Transformations也是對MediatorLiveData的使用收叶。)

LiveData的使用就講完了,下面開始源碼分析共苛。

三判没、源碼分析

前面提到 LiveData幾個特點蜓萄,能感知生命周期狀態(tài)變化、不用手動解除觀察等等澄峰,這些是如何做到的呢绕德?

3.1 添加觀察者

LiveData原理是觀察者模式,下面就先從LiveData.observe()方法看起:

    /**
     * 添加觀察者. 事件在主線程分發(fā). 如果LiveData已經(jīng)有數(shù)據(jù)摊阀,將直接分發(fā)給observer耻蛇。
     * 觀察者只在LifecycleOwner活躍時接受事件,如果變?yōu)镈ESTROYED狀態(tài)胞此,observer自動移除臣咖。
     * 當數(shù)據(jù)在非活躍時更新,observer不會接收到漱牵。變?yōu)榛钴S時 將自動接收前面最新的數(shù)據(jù)夺蛇。 
     * LifecycleOwner非DESTROYED狀態(tài)時,LiveData持有observer和 owner的強引用酣胀,DESTROYED狀態(tài)時自動移除引用刁赦。
     * @param owner    控制observer的LifecycleOwner
     * @param observer 接收事件的observer
     */
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // LifecycleOwner是DESTROYED狀態(tài)弥奸,直接忽略
            return;
        }
        //使用LifecycleOwner阅仔、observer 組裝成LifecycleBoundObserver,添加到mObservers中
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers中.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
        //!existing.isAttachedTo(owner)說明已經(jīng)添加到mObservers中的observer指定的owner不是傳進來的owner勉盅,就會報錯“不能添加同一個observer卻不同LifecycleOwner”
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;//這里說明已經(jīng)添加到mObservers中,且owner就是傳進來的owner
        }
        owner.getLifecycle().addObserver(wrapper);
    }

首先是判斷LifecycleOwner是DESTROYED狀態(tài)铆农,就直接忽略牺氨,不能添加。接著使用LifecycleOwner墩剖、observer 組裝成LifecycleBoundObserver包裝實例wrapper猴凹,使用putIfAbsent方法observer-wrapper作為key-value添加到觀察者列表mObservers中。(putIfAbsent意思是只有列表中沒有這個observer時才會添加岭皂。)

然后對添加的結果進行判斷郊霎,如果mObservers中已經(jīng)存在此observer key,但value中的owner不是傳進來的owner爷绘,就會報錯“不能添加同一個observer卻是不同LifecycleOwner”书劝。如果是相同的owner,就直接returne揉阎。

最后用LifecycleOwner的Lifecycle添加observer的封裝wrapper庄撮。

另外背捌,再看observeForever方法:

    @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

和observe()類似毙籽,只不過 會認為觀察者一直是活躍狀態(tài),且不會自動移除觀察者毡庆。

3.2 事件回調

LiveData添加了觀察者LifecycleBoundObserver坑赡,接著看如何進行回調的:

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

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }

        @Override
        boolean shouldBeActive() { //至少是STARTED狀態(tài)
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);//LifecycleOwner變成DESTROYED狀態(tài)烙如,則移除觀察者
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

LifecycleBoundObserver是LiveData的內部類,是對原始Observer的包裝毅否,把LifecycleOwner和Observer綁定在一起亚铁。當LifecycleOwner處于活躍狀態(tài),就稱 LifecycleBoundObserver是活躍的觀察者螟加。

它實現(xiàn)自接口LifecycleEventObserver徘溢,實現(xiàn)了onStateChanged方法。上一篇Lifecycle中提到onStateChanged是生命周期狀態(tài)變化的回調捆探。

在LifecycleOwner生命周期狀態(tài)變化時 判斷如果是DESTROYED狀態(tài)然爆,則移除觀察者。LiveData自動移除觀察者特點就來源于此黍图。 如果不是DESTROYED狀態(tài)曾雕,將調用父類ObserverWrapper的activeStateChanged()方法處理 這個生命周期狀態(tài)變化,shouldBeActive()的值作為參數(shù)助被,至少是STARTED狀態(tài)為true剖张,即活躍狀態(tài)為true。

    private abstract class ObserverWrapper {
        ...
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;//活躍狀態(tài) 未發(fā)生變化時揩环,不會處理搔弄。
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;//沒有活躍的觀察者
            LiveData.this.mActiveCount += mActive ? 1 : -1;//mActive為true表示變?yōu)榛钴S
            if (wasInactive && mActive) {
                onActive();//活躍的觀察者數(shù)量 由0變?yōu)?
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive(); //活躍的觀察者數(shù)量 由1變?yōu)?
            }
            if (mActive) {
                dispatchingValue(this);//觀察者變?yōu)榛钴S,就進行數(shù)據(jù)分發(fā)
            }
        }
    }

ObserverWrapper也是LiveData的內部類丰滑。mActive是ObserverWrapper的屬性肯污,表示此觀察者是否活躍。如果活躍狀態(tài) 未發(fā)生變化時吨枉,不會處理蹦渣。

LiveData.this.mActiveCount == 0 是指 LiveData 的活躍觀察者數(shù)量∶餐ぃ活躍的觀察者數(shù)量 由0變?yōu)?柬唯、由1變?yōu)? 會分別調用LiveData的 onActive()、onInactive()方法圃庭。這就是前面提到的擴展使用的回調方法锄奢。

最后觀察者變?yōu)榛钴S,就使用LiveData的dispatchingValue(observerWrapper)進行數(shù)據(jù)分發(fā):

    void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;//如果當前正在分發(fā)剧腻,則分發(fā)無效拘央,return
            return;
        }
        mDispatchingValue = true; //標記正在分發(fā)
        do {
            mDispatchInvalidated = false; 
            if (initiator != null) {
                considerNotify(initiator); //observerWrapper不為空,使用considerNotify()通知真正的觀察者
                initiator = null;
            } else { //observerWrapper為空书在,遍歷通知所有的觀察者
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false; 
    }

如果當前正在分發(fā)灰伟,則分發(fā)無效;observerWrapper不為空儒旬,就使用considerNotify()通知真正的觀察者栏账,observerWrapper為空 則遍歷通知所有的觀察者帖族。 observerWrapper啥時候為空呢?這里先留個疑問挡爵。 繼續(xù)看considerNotify()方法:

    private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return; //觀察者非活躍 return
        }
        //若當前observer對應owner非活躍竖般,就會再調用activeStateChanged方法,并傳入false茶鹃,其內部會再次判斷
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);//回調真正的mObserver的onChanged方法
    }

先進行狀態(tài)檢查:觀察者是非活躍就return涣雕;若當前observer對應的owner非活躍,就會再調用activeStateChanged方法闭翩,并傳入false胞谭,其內部會再次判斷。最后回調真正的mObserver的onChanged方法男杈,值是LivaData的變量mData丈屹。

到這里回調邏輯也通了。

3.3 數(shù)據(jù)更新

LivaData數(shù)據(jù)更新可以使用setValue(value)伶棒、postValue(value)旺垒,區(qū)別在于postValue(value)用于 子線程:

//LivaData.java
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue); //也是走到setValue方法
        }
    };

    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);//拋到主線程
    }

postValue方法把Runable對象mPostValueRunnable拋到主線程,其run方法中還是使用的setValue()肤无,繼續(xù)看:

    @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

setValue()把value賦值給mData先蒋,然后調用dispatchingValue(null),參數(shù)是null宛渐,對應前面提到的observerWrapper為空的場景竞漾,即 遍歷所有觀察者 進行分發(fā)回調。

到這里觀察者模式完整的實現(xiàn)邏輯就梳理清晰了:LivaData通過observe()添加 與LifecycleOwner綁定的觀察者窥翩;觀察者變?yōu)榛钴S時回調最新的數(shù)據(jù)业岁;使用setValue()、postValue()更新數(shù)據(jù)時會通知回調所有的觀察者寇蚊。

3.4 Transformations原理

最后來看下Transformations的map原理笔时,如何實現(xiàn)數(shù)據(jù)修改的。switchMap類似的仗岸。

//Transformations.java
    public static <X, Y> LiveData<Y> map(@NonNull LiveData<X> source,@NonNull final Function<X, Y> mapFunction) {
        final MediatorLiveData<Y> result = new MediatorLiveData<>();
        result.addSource(source, new Observer<X>() {
            @Override
            public void onChanged(@Nullable X x) {
                result.setValue(mapFunction.apply(x));
            }
        });
        return result;
    }

new了一個MediatorLiveData實例允耿,然后將 傳入的livaData、new的Observer實例作為參數(shù) 調用addSource方法:

//MediatorLiveData.java
    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
        Source<S> e = new Source<>(source, onChanged);
        Source<?> existing = mSources.putIfAbsent(source, e);
        if (existing != null && existing.mObserver != onChanged) {
            throw new IllegalArgumentException(
                    "This source was already added with the different observer");
        }
        if (existing != null) {
            return;
        }
        if (hasActiveObservers()) {
        //MediatorLiveData有活躍觀察者扒怖,就plug
            e.plug();
        }
    }

MediatorLiveData是LiveData的子類较锡,用來觀察其他的LiveData并在其OnChanged回調時 做出響應。傳入的livaData盗痒、Observer 包裝成Source實例蚂蕴,添加到列表mSources中。

如果MediatorLiveData有活躍觀察者,就調用plug():

//MediatorLiveData.java
    private static class Source<V> implements Observer<V> {
        final LiveData<V> mLiveData;
        final Observer<? super V> mObserver;
        int mVersion = START_VERSION;

        Source(LiveData<V> liveData, final Observer<? super V> observer) {
            mLiveData = liveData;
            mObserver = observer;
        }

        void plug() {
            mLiveData.observeForever(this);//observeForever
        }

        void unplug() {
            mLiveData.removeObserver(this);
        }

        @Override
        public void onChanged(@Nullable V v) {
            if (mVersion != mLiveData.getVersion()) {
                mVersion = mLiveData.getVersion();
                mObserver.onChanged(v);//源LiveData數(shù)據(jù)變化時及時回調到 傳入的
            }
        }
    }

Source是MediatorLiveData的內部類掂墓,是對源LiveData的包裝。plug()中讓源LiveData調用observeForever方法添加永遠觀察者-自己看成。 這里為啥使用observeForever方法呢君编,這是因為源LiveData在外部使用時不會調用observer方法添加觀察者,這里永遠觀察是為了在源LiveData數(shù)據(jù)變化時及時回調到 mObserver.onChanged(v)方法川慌,也就是Transformations map方法中的nChanged方法吃嘿。 而在e.plug()前是有判斷 MediatorLiveData 確認有活躍觀察者的。

最后map方法中的nChanged方法中有調用MediatorLiveData實例的setValue(mapFunction.apply(x)); 并返回實例梦重。而mapFunction.apply()就是map方法傳入的修改邏輯Function實例兑燥。

最后類關系圖:

LiveData類關系

四、總結

本文先介紹了LiveData的概念——使用觀察者并可以感知生命周期琴拧,然后是使用方式降瞳、自定義LivaData、高級用法Transformations蚓胸。最后詳細分析了LiveData源碼及原理挣饥。

并且可以看到Lifecycle如何在LiveData中發(fā)揮作用,理解了觀察者模式在其中的重要運用沛膳。LiveData是我們后續(xù)建立MVVM架構的核心扔枫。 LiveData同樣是我們必須掌握和理解的部分。

下一篇將介紹ViewModel锹安,同樣是AAC中的核心內容短荐。 今天就到這里啦~

.

感謝與參考:

Livedata官方文檔

Android Jetpack架構組件(五)一文帶你了解LiveData(原理篇)

.

你的 點贊、評論叹哭,是對我的巨大鼓勵忍宋!

歡迎關注我的 公 眾 號,微信搜索 胡飛洋 风罩,文章更新可第一時間收到讶踪。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市泊交,隨后出現(xiàn)的幾起案子乳讥,更是在濱河造成了極大的恐慌,老刑警劉巖廓俭,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件云石,死亡現(xiàn)場離奇詭異,居然都是意外死亡研乒,警方通過查閱死者的電腦和手機汹忠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宽菜,你說我怎么就攤上這事谣膳。” “怎么了铅乡?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵继谚,是天一觀的道長。 經(jīng)常有香客問我阵幸,道長花履,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任挚赊,我火速辦了婚禮诡壁,結果婚禮上,老公的妹妹穿的比我還像新娘荠割。我一直安慰自己妹卿,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布蔑鹦。 她就那樣靜靜地躺著纽帖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪举反。 梳的紋絲不亂的頭發(fā)上懊直,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音火鼻,去河邊找鬼室囊。 笑死,一個胖子當著我的面吹牛魁索,可吹牛的內容都是我干的融撞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼粗蔚,長吁一口氣:“原來是場噩夢啊……” “哼尝偎!你這毒婦竟也來了?” 一聲冷哼從身側響起鹏控,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤致扯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后当辐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抖僵,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年缘揪,在試婚紗的時候發(fā)現(xiàn)自己被綠了耍群。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片义桂。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蹈垢,靈堂內的尸體忽然破棺而出慷吊,到底是詐尸還是另有隱情,我是刑警寧澤曹抬,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布溉瓶,位于F島的核電站,受9級特大地震影響沐祷,放射性物質發(fā)生泄漏嚷闭。R本人自食惡果不足惜攒岛,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一赖临、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧灾锯,春花似錦兢榨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兼雄,卻和暖如春吟逝,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赦肋。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工块攒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人佃乘。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓囱井,卻偏偏與公主長得像,于是被迫代替她去往敵國和親趣避。 傳聞我的和親對象是個殘疾皇子庞呕,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內容