Jetpack第三篇:LiveData

1、什么是LiveData

基于觀察者的消息訂閱/分發組件,依靠Lifecycles確保LiveData的數據僅分發給處于活躍狀態的觀察者。

2、LiveData的使用

  • 導入依賴
implementation  'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'

LiveData在實戰中一般都是作為網絡請求的數據分發,LiveData本身就是一個觀察者模式,在實戰中,網絡請求的時候,LiveData便將數據分發出去。

MutableLiveData繼承了LiveData,一般都用MutableLiveData來做數據分發使用。還有一種MediatorLiveData也繼承了LiveData,后面會講到。

  • MutableLiveData使用

class MainActivity : AppCompatActivity() {
  var liveData1: MutableLiveData<Int> = MutableLiveData()
  var liveData2: MutableLiveData<String> = MutableLiveData()
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      // 注冊觀察者
      startObserver()
      // 數據發生改變
      liveData1.postValue(1000)
      liveData2.postValue("33333")
  }
  private fun startObserver() {
      liveData1.observe(this, Observer {
          Log.i("liveData1",it.toString())
      })
      liveData2.observe(this, Observer {
          Log.i("liveData2",it.toString())
      })
  }
}

結果:

10-17 05:52:45.645 4197-4197/com.mg.axechen.testdemo I/liveData1: 1000
10-17 05:52:45.645 4197-4197/com.mg.axechen.testdemo I/liveData2: 33333
  • MediatorLiveData
    MediatorLiveData可以通過addSource將所有的MutableLiveData統一觀察,當然他自己也是繼承了LiveData,也可以被其他的Observer觀察。

class MainActivity : AppCompatActivity() {
  var liveData1: MutableLiveData<Int> = MutableLiveData()
  var liveData2: MutableLiveData<String> = MutableLiveData()
  var mediatorLiveData: MediatorLiveData<Any> = MediatorLiveData()
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      mediatorLiveData.addSource(liveData1,dataObserver2)
      mediatorLiveData.addSource(liveData2,dataObserver)
      mediatorLiveData.observe(this, Observer {
          Log.i("liveData5",it.toString())
      })
      liveData1.value = 1000
      liveData2.value = "axeChen"
      mediatorLiveData.postValue("xxxx")
  }
  private var dataObserver2 = object :Observer<Int>{
      override fun onChanged(t: Int?) {
          Log.i("liveData4",t.toString())
      }
  }
  private var dataObserver =object :Observer<Any> {
      override fun onChanged(t: Any?) {
          Log.i("liveData3",t.toString())
      }
  }
}

輸出結果:

10-17 06:02:21.624 4713-4713/com.mg.axechen.testdemo I/liveData4: 1000
10-17 06:02:21.624 4713-4713/com.mg.axechen.testdemo I/liveData3: axeChen
10-17 06:02:21.637 4713-4713/com.mg.axechen.testdemo I/liveData5: xxxx

3、LiveData源碼解析

3.1、LiveData的關鍵類

LiveData

public abstract class LiveData<T> {}

類聲明可以看出這個是一個抽象類,它封裝了訂閱和取消訂閱的方法:

// 訂閱Observer的方法
public void observe(@NonNull LifecycleOwner owner, 
                       @NonNull Observer<? super T> observer) {}
public void observeForever(@NonNull Observer<? super T> observer) {}  

// 取消訂閱Observer的方法
public void removeObserver(@NonNull final Observer<? super T> observer) {}
public void removeObservers(@NonNull final LifecycleOwner owner) {}

封裝了Observerapper的子類LifecycleBoundObserver和AlwaysActiveObserver,關于Observerapper這個類,只要知道這個是用于分發數據的類,具體如何分發下面會分析到。

class LifecycleBoundObserver extends
 ObserverWrapper implements LifecycleEventObserver {} 
 private class AlwaysActiveObserver extends ObserverWrapper {}

LifecycleBoundObserver
生命周期安全的Observer。

class LifecycleBoundObserver extends
 ObserverWrapper implements LifecycleEventObserver {}

AlwaysActiveObserver
非生命周期的Observer。

private class AlwaysActiveObserver extends ObserverWrapper {}
3.2、關鍵方法

兩種訂閱方式
上面提到了生命周期安全的概念,最大的區別就是在分發數據的時候是否考慮到了生命周期。考慮和非考慮生命周期安全的方式訂閱的方式也不一樣。
LiveData中observer方法是考慮生命周期安全的訂閱方式。
observer考慮生命周期安全的方式訂閱

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
  // 1、判斷是否在主線程中
        assertMainThread("observe");
        // 2、判斷當前宿主狀態是不是Destory,假如是Destory則直接return
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // ignore
            return;
        }
        // 3、封裝成LifecycleBoundObserver ,
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // 4、判斷是否已經存在了Observer
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // 5、假日已經存在了Observer則拋出異常
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        // 6、訂閱觀察者
        owner.getLifecycle().addObserver(wrapper);
    }

看下LifecycleBoundObserver的代碼,onStateChanged是分發狀態的方法。


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() {
        // 這里用了狀態枚舉的比較方法,去看isAtLeast方法就會明白,
        // 只有當狀態為STARTED或者RESUMED算為活躍狀態,返回true
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        // 1、獲取當前宿主的生命周期狀態
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        
        // 2、判斷狀態是不是Destory
        if (currentState == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        // 3、while阻塞線程
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }

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

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

activeStateChanged,中傳入是不是宿主是不是活躍的狀態。如果是活躍狀態則調用dispatchingValue。

void activeStateChanged(boolean newActive) {
    if (newActive == mActive) {
        return;
    }
    // immediately set active state, so we'd never dispatch anything to inactive
    // owner
    mActive = newActive;
    changeActiveCounter(mActive ? 1 : -1);
    if (mActive) {
        // 分發值
        dispatchingValue(this);
    }
}

不考慮生命周期安全的observerForver

observerForver和observer最大的區別就是沒有傳入LifecycleOwner,不會考慮生命周期的變化。只要數據發生變化時就會進行數據回調。


@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
    // 1、判斷是不是主線程
    assertMainThread("observeForever");
    // 2、封裝成AlwaysActiveObserver
    AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
    // 3、判斷是不是已經存在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;
    }
    // 4、回調數據
    wrapper.activeStateChanged(true);
}
@SuppressWarnings("WeakerAccess") /* synthetic access */
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            // 當initiator 不為空就將這發送給自己,這個在Observer注冊的時候會調用
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                   // 遍歷所有的Observer并分發數據
                 considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

AlwaysActiveObserver
最終分發數據的方法是considerNotify

private class AlwaysActiveObserver extends ObserverWrapper {

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

    @Override
    boolean shouldBeActive() {
        // 永久返回True
        return true;
    }
}
private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
    //
    // we still first check observer.active to keep it as the entrance for events. So even if
    // the observer moved to an active state, if we've not received that event, we better not
    // notify for a more predictable notification order.
    
    // 判斷宿主是否處于活躍狀態
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 是不是已經分發過數據了
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    // 同步Version
    observer.mLastVersion = mVersion;
    // 分發數據
    observer.mObserver.onChanged((T) mData);
}

從AlwaysActiveObserver可以看到,shouldBeActive()永久為true。只要有數據就會立即回調。
代碼中已經非常明白了,先判斷是不是處于活躍狀態。然后再分發數據。

3.3、移除訂閱

這個就是將訂閱移除掉

@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
    assertMainThread("removeObserver");
    ObserverWrapper removed = mObservers.remove(observer);
    if (removed == null) {
        return;
    }
    removed.detachObserver();
    removed.activeStateChanged(false);
}

@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
    assertMainThread("removeObservers");
    for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
        if (entry.getValue().isAttachedTo(owner)) {
            removeObserver(entry.getKey());
        }
    }
}
3.4、PostValue()、setValue()

從一開始的例子可以知道,如果調用了這兩個方法,liveData.observer{}就可以觀察到值的變化,從而獲取到新的值。這兩個方法是更新LiveData值的方法。

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

這兩個的區別:

  • 1、setValue只能在主線程中調用。
  • 2、postValue能在子線程中調用,具有同步鎖的功能。
  • 3、postValue多次調用只有最后一個值才有效。

4、總結

LiveData使用的時候會根據宿主是不是活躍去分發數據,減少了一些因為Activity,Fragment不可見而處理數據,浪費了資源的情況,使用時盡量使用安全的訂閱方式和postValue方法。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容