Android Jetpack 之 LiveData

概述

  • LiveData 是一個持有數據的類,它持有的數據是能夠被觀察者訂閱的,當數據被修改時就會通知觀察者。觀察者能夠是 Activity、Fragment、Service 等。
  • LiveData 可以感知觀察者的生命週期,只有當觀察者處於激活狀態(STARTED、RESUMED)纔會接收到數據更新的通知,在未激活時會自動解註冊觀察者,以減小內存泄漏。
  • 使用 LiveData 保存數據時,因爲數據和組件是分離的,當組件重建時能夠保證數據不會丟失。

優勢

  • 確保 UI 界面始終和數據狀態保持一致。
  • 沒有內存泄漏,觀察者綁定到 Lifecycle 對象並在其相關生命週期 destroyed 後自行解除綁定。
  • 不會由於 Activity 中止了而奔潰,如 Activity finish 了,它就不會收到任何 LiveData 事件了。
  • UI 組件只需觀察相關數據,不須要中止或恢復觀察,LiveData 會自動管理這些操做,由於 LiveData 能夠感知生命週期狀態的更改。
  • 在生命週期從非激活狀態變爲激活狀態,始終保持最新數據,如後臺 Activity 在返回到前臺後能夠當即收到最新數據。
  • 當配置發生更改(如屏幕旋轉)而重建 Activity / Fragment,它會當即收到最新的可用數據。
  • LiveData 很適合用於組件(Activity / Fragment)之間的通訊。

使用

添加相關依賴java

LiveData 有兩種使用方式,結合 ViewModel 使用以及直接繼承 LiveData 類。android

結合 ViewModel 使用git

如下代碼場景:點擊按鈕提示一個名字。github

class MyViewModel : ViewModel() {

    // 建立一個 String 類型的 LiveData
    // MutableLiveData 是抽象類 LiveData 的子類,咱們通常使用的是 MutableLiveData
    private lateinit var name: MutableLiveData<String>

    fun getName(): MutableLiveData<String> {
        if (!::name.isInitialized) {
            name = MutableLiveData()
        }
        return name
    }
}
複製代碼
class LiveDataActivity : AppCompatActivity() {

    private lateinit var myViewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        // 建立並註冊觀察者
        myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)
        myViewModel.getName().observe(this, Observer {
            // LiveData 數據更新回調,it 表明被觀察對象的數據,此處爲 name
            Toast.makeText(baseContext, it, Toast.LENGTH_SHORT).show()
        })

        btnSetName.setOnClickListener {
            // 使用 setValue 的方式更新 LiveData 數據
            myViewModel.getName().value = "張三"
        }
    }
}
複製代碼

讓數據(name)和組件(LiveDataActivity)分離,當 Activity 重建時,數據(name)不會丟失。架構

直接繼承 LiveData 類app

如下代碼場景:在 Activity 中監聽 Wifi 信號強度。ide

class WifiLiveData private constructor(context: Context) : LiveData<Int>() {

    private var mContext: WeakReference<Context> = WeakReference(context)

    companion object {

        private var instance: WifiLiveData? = null

        fun getInstance(context: Context): WifiLiveData {
            if (instance == null) {
                instance = WifiLiveData(context)
            }
            return instance!!
        }
    }

    override fun onActive() {
        super.onActive()
        registerReceiver()
    }

    override fun onInactive() {
        super.onInactive()
        unregisterReceiver()
    }

    /** * 註冊廣播,監聽 Wifi 信號強度 */
    private fun registerReceiver() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(WifiManager.RSSI_CHANGED_ACTION)
        mContext.get()!!.registerReceiver(mReceiver, intentFilter)
    }

    /** * 註銷廣播 */
    private fun unregisterReceiver() {
        mContext.get()!!.unregisterReceiver(mReceiver)
    }

    private val mReceiver = object : BroadcastReceiver() {

        override fun onReceive(context: Context?, intent: Intent) {
            when (intent.action) {
                WifiManager.RSSI_CHANGED_ACTION -> getWifiLevel()
            }
        }
    }

    private fun getWifiLevel() {
        val wifiManager = mContext.get()!!.applicationContext.getSystemService(android.content.Context.WIFI_SERVICE) as WifiManager
        val wifiInfo = wifiManager.connectionInfo
        val level = wifiInfo.rssi

        instance!!.value = level // 發送 Wifi 的信號強度給觀察者
    }
}
複製代碼
class LiveDataActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_live_data)

        withExtendsLiveDataTest()
    }

    /** * 直接繼承 LiveData 類 */
    private fun withExtendsLiveDataTest() {
        WifiLiveData.getInstance(this).observe(this, Observer {
            Log.e("LiveDataActivity", it.toString()) // 觀察者收到數據更新的通知,打印 Wifi 信號強度
        })
    }
}
複製代碼

當組件(Activity)處於激活狀態(onActive)時註冊廣播,處於非激活狀態(onInactive)時註銷廣播。post

源碼解析

observe 註冊流程

LiveData 經過 observe() 方法將被觀察者 LifecycleOwner (Activity / Fragment) 和觀察者 Observer 關聯起來。ui

LiveData.observe(LifecycleOwner owner , Observer<T> observer)
複製代碼

進入 LiveData 的 observe() 方法中this

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // 若 LifecycleOwner 處於 DESTROYED 狀態,則返回
        return;
    }

    // LifecycleBoundObserver 把 LifecycleOwner 對象和 Observer 對象包裝在一塊兒
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);

    // mObservers(相似 Map 的容器)的 putIfAbsent() 方法用於判斷容器中的 observer(key)
    // 是否已有 wrapper(value)與之關聯
    // 若已關聯則直接返回關聯值,不然關聯後再返回 wrapper
    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;
    }

    // 因爲 LifecycleBoundObserver 實現了 GenericLifecycleObserver 接口,而 GenericLifecycleObserver 又
    // 繼承了 LifecycleObserver,因此 LifecycleBoundObserver 本質是一個 LifecycleObserver
    // 此處屬於註冊過程, Lifecycle 添加觀察者 LifecycleObserver
    owner.getLifecycle().addObserver(wrapper);
}
複製代碼

從上面的代碼可知,observe() 方法最終是會調用 LifecycleOwner.getLifecycle().addObserver(LifecycleObserver) ,所以 LiveData 是可以感知觀察者的生命週期變化的。

感知生命週期變化

經過以上的分析,咱們知道 LifecycleBoundObserver(LiveData 的內部類)是觀察者,如下具體分析 LifecycleBoundObserver 的實現過程。

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

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

    @Override
    boolean shouldBeActive() {
        // 判斷是否處於激活狀態
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }


    @Override
    public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
        // 若 Lifecycle 處於 DESTROYED 狀態,則移除 Observer 對象
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            // 移除觀察者,在這個方法中會移除生命週期監聽而且回調 activeStateChanged() 方法
            removeObserver(mObserver);
            return;
        }
        // 若處於激活狀態,則調用 activeStateChanged() 方法
        activeStateChanged(shouldBeActive());
    }

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

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}
複製代碼

當組件(Activity / Fragment)的生命週期發生改變時,onStateChanged() 方法將會被調用。若當前處於 DESTROYED 狀態,則會移除觀察者;若當前處於激活狀態,則會調用 activeStateChanged() 方法。activeStateChanged() 方法位於父類 ObserverWrapper 中。

void activeStateChanged(boolean newActive) {
    // 若新舊狀態一致,則返回
    if (newActive == mActive) {
        return;
    }
    // immediately set active state, so we'd never dispatch anything to inactive owner
    mActive = newActive;
    boolean wasInactive = LiveData.this.mActiveCount == 0;
    LiveData.this.mActiveCount += mActive ? 1 : -1;
    if (wasInactive && mActive) { // 激活狀態的 observer 個數從 0 到 1
        onActive(); // 空實現,通常讓子類去重寫
    }
    if (LiveData.this.mActiveCount == 0 && !mActive) { // 激活狀態的 observer 個數從 1 到 0
        onInactive();  // 空實現,通常讓子類去重寫
    }
    if (mActive) { // 激活狀態,向觀察者發送 LiveData 的值
        dispatchingValue(this);
    }
}
複製代碼

再看看最終調用的 dispatchingValue() 方法。

private void dispatchingValue(@Nullable ObserverWrapper initiator) {
    // ...
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            // 循環遍歷 mObservers 這個 map , 向每個觀察者都發送新的數據
            for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    // ...
}
複製代碼

能夠看到 dispatchingValue() 方法裏面再經過 considerNotify() 方法將消息通知下去。

private void considerNotify(ObserverWrapper observer) {
    // ...
    observer.mObserver.onChanged((T) mData);
}
複製代碼

上面的 mObserver 正是咱們調用 observe() 方法時傳入的觀察者。

總結上面的分析就是:調用 LiveData.observe(LifecycleOwner owner , Observer observer) 進行註冊後,當 LiveData 數據發生變化後,最終就會調用 Observer 對象的 onChanged() 方法,並把變化的數據做爲參數回傳。

通知觀察者更新數據的方式

LiveData 爲咱們提供了兩種改變數據後,通知觀察者更新數據的方式,一個是 setValue() 方法(必須在主線程調用),另外一個是 postValue() 方法(必須在子線程調用)。

setValue() 方法

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

dispatchingValue() 方法會跑咱們上面分析的流程,最終把改變的數據 value(對應上面的 mData)做爲 onChanged() 方法的參數傳給觀察者。

postValue() 方法

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

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        //noinspection unchecked
        setValue((T) newValue);
    }
};
複製代碼

能夠看出 postValue() 方法最終也會在主線程中調用 setValue() 方法。

文中 Demo GitHub 地址

參考資料:

相關文章
相關標籤/搜索