91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Android?Jetpack組件LiveData源碼分析

發布時間:2023-03-10 17:28:11 來源:億速云 閱讀:114 作者:iii 欄目:開發技術

本篇內容主要講解“Android Jetpack組件LiveData源碼分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Android Jetpack組件LiveData源碼分析”吧!

基本使用

一般來說 LiveData 都會配合 ViewModel 使用,篇幅原因關于 ViewModel 的內容將在后續博客中分析,目前可以將 ViewModel 理解為一個生命周期比 Activity 更長的對象,且不會造成內存泄漏。

示例代碼:

MainViewModel.kt

class MainViewModel: ViewModel() {
    // 定義 LiveData 注意這里給了 0 作為初始值
    val number = MutableLiveData<Int>(0)
    fun add(){
        // 相當于 number.setValue(number.getValue() + 1)
        number.value = number.value?.plus(1)
    }
    fun sub(){
        // 相當于 number.setValue(number.getValue() - 1)
        number.value = number.value?.minus(1)
    }
}

MainACtivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 獲取 ViewModel 實例
        val vm = ViewModelProvider(this).get(MainViewModel::class.java)
        // 調用 ViewModel 方法 進行加法操作
        bnAdd.setOnClickListener {
             vm.add()
        }
        // 調用 ViewModel 方法 進行減法操作
        bnSub.setOnClickListener {
            vm.sub()
        }
        // 觀察 LiveData 變化, Observer 是接口,kotlin 寫法簡化
        vm.number.observe(this, Observer {
            tvNumber.text = it.toString()
        })
    }
}

疑問

很簡單的功能,但是有兩個問題需要注意:

  • 在 XML 中并沒有給中間的 TextView 設置 text 屬性,僅僅給 LiveData 賦值了初始值 0,就可以直接顯示到 TextView 上;

  • 數值發生變化后,進行橫豎屏切換后 TextView 依然保持著最新值(如果 number 作為普通 Int 放在 Activity 中,當 Activity 由于橫豎屏切換導致重建會重新變為 0);

本文將以這兩個問題作為切入點,對 LiveData 源碼進行分析。

源碼分析

Observer

從實例代碼中很容易看出這是典型的觀察者模式,當 LiveData 發生變化時會對其訂閱者發送通知,將最新值傳遞過去,Observer 就相當于其觀察者,先來看一下 Observer 接口:

public interface Observer<T> {
    void onChanged(T t);
}

當 LiveData 發生變化時,就會觸發其觀察者的 onChanged 方法,并傳遞最新值;

再看一下其添加訂閱時的源碼:

public abstract class LiveData<T> {
    //...
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        // 檢查是否在主線程
        assertMainThread("observe");
        // 如果觀察者所在組件的生命周期為 DESTROYED 則直接 return
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            return;
        }
        // LifecycleBoundObserver 實現了 ObserverWrapper
        // 理解為這是對 觀察者 Observer 的一層包裝類即可
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        // mObservers 是一個 Map 容器,原始的 Observer 為 key,包裝后的 wrapper 為 value
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        // 同一個 observer 不能在不同的生命周期組件中進行訂閱
        if (existing != null && !existing.isAttachedTo(owner)) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        // 重復訂閱直接return
        if (existing != null) {
            return;
        }
        // LifecycleBoundObserver 利用 Lifecycle 實現自動解綁
        // Lifecycle 原理詳見我之前的博客
        owner.getLifecycle().addObserver(wrapper);
    }
    // ...
}

從源碼中得知訂閱必須在主線程(這一點也非常適用于 Android 的 UI 更新), 訂閱后會放入一個 Map 容器中存儲;

ObserverWrapper

接著來看一下 LiveData 是如何對 Observer 進行包裝的,LifecycleBoundObserver 實現了 ObserverWrapper,那么就先來看看 ObserverWrapper 的源碼:

private abstract class ObserverWrapper {
    final Observer<? super T> mObserver; // Observer 原始對象
    boolean mActive; // 是否激活
    int mLastVersion = START_VERSION; // 版本號 默認 -1
    ObserverWrapper(Observer<? super T> observer) {
        mObserver = observer; // 賦值
    }
    abstract boolean shouldBeActive(); // 抽象方法
    boolean isAttachedTo(LifecycleOwner owner) {
        return false;
    }
    void detachObserver() {
    }
    void activeStateChanged(boolean newActive) {
        if (newActive == mActive) { // 如果值一樣則返回
            return;
        }
        mActive = newActive; // 不一樣則更新 mActive
        changeActiveCounter(mActive ? 1 : -1); // 記錄有多少個激活狀態的observer
        // 注意這里,如果mActive是從false變更為true 則調用一次 dispatchingValue
        // dispatchingValue 的源碼下面再分析
        if (mActive) { 
            dispatchingValue(this);
        }
    }
}
LifecycleBoundObserver

接著看一下 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() { // 判斷是否是激活狀態
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }
    // 如果再 activity 中進行 observer
    // 當 activity 生命周期發生變化時 會回調到這里
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
        // 自動解綁
        if (currentState == DESTROYED) { 
            // removeObserver 內部會將 observer 從 map 容器中移除
            // 并且調用其 detachObserver 方法
            removeObserver(mObserver);
            return;
        }
        Lifecycle.State prevState = null;
        while (prevState != currentState) {
            prevState = currentState;
            // activeStateChanged 上面已經說過了
            // 如果 mActive 由 fasle 變更為 true 會執行一次 dispatchingValue
            activeStateChanged(shouldBeActive());
            currentState = mOwner.getLifecycle().getCurrentState();
        }
    }
    // ...
}

MutableLiveData

上述的觀察者相關的重要源碼已經分析完,接著來看一下示例代碼中定義的 MutableLiveData 源碼:

public class MutableLiveData<T> extends LiveData<T> {
    public MutableLiveData(T value) {
        super(value);
    }
    public MutableLiveData() {
        super();
    }
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }
    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

繼承自 LiveData,作用很明顯暴露出其 postValue、setValue 方法,那么就先來看一下這兩個方法調用邏輯

postValue

先來看看 postValue:

public abstract class LiveData<T> {
    protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            // mPendingData 默認值為 NOT_SET
            postTask = mPendingData == NOT_SET;
            // 調用 postValue 后,會賦值成傳進來的 value
            mPendingData = value; 
        }
        if (!postTask) { // 第一次調用 肯定為 true
            return;
        }
        // 核心在于這一行,postToMainThread 
        // 看名字也知道是切換到主線程去執行 mPostValueRunnable
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }
}

ArchTaskExecutor.getInstance() 會初始化其內部的 mDelegate 變量,其最終實現是 DefaultTaskExecutor;DefaultTaskExecutor 內部包含一個主線程 Handler,其 postToMainThread 方法就是利用 Handler 將 runnable 發送至主線程執行。這里面的源碼比較簡單,就不貼出來細節了,看一下 mPostValueRunnable 具體執行了什么:

private final Runnable mPostValueRunnable = new Runnable() {
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) { // 加鎖同步
            newValue = mPendingData; // 獲取最新傳遞過來的值
            mPendingData = NOT_SET; // 將 mPendingData 恢復為默認值
        }
        // 最終還是調用了 setValue
        setValue((T) newValue);
    }
};

可以看出 postValue 可以在任意線程調用,最終都會被切換到主線程調用 setValue,但是需要注意,頻繁調用 postValue 可能會只保留最后一次的值,因為每次 postValue 會導致 mPendingData 設置為新的值,但如果多次 postValue 在子線程執行,但是主線程還沒有來得及執行 mPostValueRunnable,會導致 mPendingData 沒有被恢復為 NOT_SET,那么 postTask 即為 false,但 mPendingData 會設置為最新值,當 mPostValueRunnable 執行時從 mPendingData 中獲取的也是最新值。

setValue

postValue 內部最終調用了 setValue,那么就來看看 setValue 的源碼:

public abstract class LiveData<T> {
    static final int START_VERSION = -1;
    private volatile Object mData;
    private int mVersion
    // 帶初始值的構造器
    public LiveData(T value) {
        mData = value; // 直接給 mData 賦值
        mVersion = START_VERSION + 1; //版本號 +1,也就是 0
    }
    // 無參構造器
    public LiveData() {
        mData = NOT_SET;
        mVersion = START_VERSION; // 版本號默認 -1
    }
    protected void setValue(T value) {
        // 內部根據 Looper 判斷是否在主線程,不在主線程則拋出異常
        assertMainThread("setValue");
        // 版本號 +1
        mVersion++;
        // LiveData 的數據,也就是被觀察的數據,設置為最新值
        mData = value;
        // 這里是重點
        dispatchingValue(null);
    }
}

從源碼中得知,setValue 只能從主線程調用,內部對版本號進行++操作,并且設置 mData 為最新值,最終調用 dispatchingValue:

// 用于保存其觀察者 Observer,Observer 會包裝成
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
        new SafeIterableMap<>();
void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) { // 默認為 false 
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true; // 進入方法后設置為 true
    do {
        mDispatchInvalidated = false; 
        // setValue 傳進來的是 null 不會進入這個 if
        // initiator 實際上就是觀察者,如果傳遞進來一個觀察者對象
        // 則只進行一次 considerNotify 方法調用
        if (initiator != null) { 
            considerNotify(initiator);
            initiator = null;
        } else { // 遍歷自身的觀察者
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                // 調用 considerNotify 將觀察者傳入
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false; // 方法執行結束前 設置為 false
}
private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) { // 未激活狀態直接返回
        return;
    }
    // 判斷是否可以是激活狀態
    // LifecycleBoundObserver 中則是判斷所在組件的生命周期是否為激活狀態
    if (!observer.shouldBeActive()) { 
        observer.activeStateChanged(false); // 將 observer 的 mActive 設置為 fasle
        return;
    }
    // 如果 observer 的版本號 大于 LiveData 本身的版本號 則直接返回
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    // 將 observer 的版本號和 LiveData 本身的版本號同步
    observer.mLastVersion = mVersion;
    // 觸發其 onChanged 方法回調
    observer.mObserver.onChanged((T) mData);
}

setValue 的源碼并不復雜,總結一下:

  • mVersion 版本號 ++ 操作,并且 mData 設置為最新數據;

  • dispatchingValue(null) 遍歷觀察者容器,對符合條件的觀察者調用其 onChanged 方法回調。

問題答疑

從源碼中我們可以了解到,當調用 LiveData.observer 時,我們傳入的 observer 對象會被包裝成為 LifecycleBoundObserver,會自動感知所在組件的生命周期;

又因為 Lifecycle 會在觀察組件生命周期之后就會進行狀態同步,所以我們再調用 LiveData.observer 之后會觸發一次 activeStateChanged,導致 observer 的 mActive 由 fasle 變為 true,所以會進行一次 dispatchingValue;

在示例代碼中我們給 MainViewModel 中的 number 賦值了初始值 0,那么初始化時會調用 LiveData 有參的構造函數,其中對 mVersion 進行了 +1 操作,此時的 LiveData 中的 mVersion 變為了 0,而 observer 中的 mLastVersion 為 -1,所以會進行一次分發,所以 TextView 的 text 被設置為了 0;

而第二個問題和上述的原因類似,不過特殊點在于 number 是被定義在在 ViewModel 中,開頭也提到過 ViewModel 暫時可以理解為生命周期長于 Activity 的對象,那么當 Activity 由于橫豎屏切換導致重建后, ViewModel 中的數據并沒有清楚,LiveData 自然保持著他的 mData 最新值以及其 mVersion 版本號,當 Actvitiy 重新調用 LiveData.observer 進行訂閱時,傳入的 observer 的 mVersion 已經變為 -1,所以同樣會觸發一次 onChanged 回調得到最新值;

LiveData 特性引出的問題

上述問題答疑中其實可以看出 LiveData 訂閱后可以獲取最新值這在數據流中屬于粘性 事件。在示例代碼中,橫豎屏切換后仍然可以獲取最新的值,這比較符合用戶使用習慣。但實際開發中往往有著更復雜的場景,比如:定義一個 LiveData<Boolean>(false) 表示是否需要展示加載中彈窗,假設需求是用戶點擊按鈕后展示,此時用戶點擊按鈕,將其設置為 true,那么此時 Activiy 發生重建導致生命周期重新走一遍,此時的 LiveData 的 value 仍然為 true,重建后用戶并沒有點擊按鈕但彈窗仍然會顯示;

這是一個很常見的業務需求,發生這種問題的根本原因是生命周期重新走之后導致 observer 的 mLastVersion 變更為 -1,而 LiveData 的 mVersion 不變,導致重新觸發 onChanged 方法回調;

遇到這種情況該怎么辦呢?難道 LiveData 設計的有問題?我認為這并非 google 官方設計的不好,而是 LiveData 本身就應該作用于時時刻刻需要獲取最新值的場景,而并非所有的數據都需要放到 ViewModel 中用 LiveData 包裹。上述的問題更多的我認為是 LiveData 濫用而導致的。 但 LiveData 的 onChanged 的數據變化后進行回調很多場景使用起來又很方便,該怎么辦?

問題解決

既然已經知道原因,源碼又了解的差不多,很容易就能找到問題的切入點;那就是 considerNotify 方法中會有層層判斷,只要有一個不符合則不會觸發 onChanged 方法回調,可以反射修改 observer 的 mLastVersion 使其重新訂閱后仍然和 LiveData 保持一致。 不過利用到了反射,那么風險度也自然提高。

還有更好的辦法,SingleLiveData!我最初看到這個類是在 github 中的一個 issue 中,后來網上流傳了很多版本,其原理是對 LiveData 進行包裝,內部定義一個 HashMap<Observer<in T>, AtomicBoolean> 容器,重寫其 observer 訂閱方法,每個 observer 對應一個 AtomicBoolean 對象,在 setValue 之前先遍歷將所有的 AtomicBoolean 設置為 true,接著重寫其 observer 包裝一層,在分發時判斷并修改 AtomicBoolean 為 false。

我覺得這也是比較好的規避問題的方法,這里就隨便貼一個了:

class SingleLiveData<T> : MutableLiveData<T>() {
    private val mPendingMap = HashMap<Observer<in T>, AtomicBoolean>()
    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
        val lifecycle = owner.lifecycle
        if (lifecycle.currentState == Lifecycle.State.DESTROYED) {
            return
        }
        mPendingMap[observer] = AtomicBoolean(false)
        lifecycle.addObserver(LifecycleEventObserver { source: LifecycleOwner?, event: Lifecycle.Event ->
            if (event == Lifecycle.Event.ON_DESTROY) {
                mPendingMap.remove(observer)
            }
        })
        super.observe(owner) { t: T ->
            val pending = mPendingMap[observer]
            if (pending != null && pending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        }
    }
    @MainThread
    override fun observeForever(observer: Observer<in T>) {
        mPendingMap[observer] = AtomicBoolean(false)
        super.observeForever(observer)
    }
    @MainThread
    override fun removeObserver(observer: Observer<in T>) {
        mPendingMap.remove(observer)
        super.removeObserver(observer)
    }
    @MainThread
    override fun removeObservers(owner: LifecycleOwner) {
        mPendingMap.clear()
        super.removeObservers(owner)
    }
    @MainThread
    override fun setValue(t: T?) {
        for (value in mPendingMap.values) {
            value.set(true)
        }
        super.setValue(t)
    }
}

到此,相信大家對“Android Jetpack組件LiveData源碼分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

嘉鱼县| 武宁县| 运城市| 岑溪市| 区。| 治县。| 瓦房店市| 宿迁市| 策勒县| 商水县| 克拉玛依市| 吉安县| 罗甸县| 怀远县| 汕头市| 青海省| 历史| 秦皇岛市| 沙洋县| 陆河县| 临武县| 平武县| 西安市| 南投县| 合山市| 祁阳县| 图们市| 钦州市| 隆尧县| 塔城市| 林州市| 长子县| 涪陵区| 曲周县| 璧山县| 岢岚县| 黎川县| 延川县| 井冈山市| 大荔县| 安泽县|