Android JetPack組件之LiveData

Android JetPack組件之LiveData

在這裏插入圖片描述

簡介

和上一篇Lifecycle組件一樣,LiveData也是一個觀察者機制的東西,訂閱者訂閱LiveData後,LiveData數據發生變化,就會通知到訂閱者;


使用步驟

  1. 創建LiveData數據
  2. 加入訂閱者到LiveData中去
  3. 改變LiveData的值
  4. 觸發通知到訂閱者

僞代碼如下:

6. val myLiveData = MutableLiveData<String>()
7. myLiveData.observe(LifecycleOwner, Observer {
            void onChanged(String t){
				Log.i("tag", t)
			}
        })
8. myLiveData.postValue("new value")
9. 打印執行new value

上面代碼就是LiveData的一個簡單使用,那麼它背後的原理如何,請看下分析


實現原理

MutableLiveData

MutableLiveData類是LiveData類的子類,基本和LiveData一樣,沒有做特別的改變;當然除了MutableLiveData子類外,還有RoomTrackingLiveData類,也是LiveData的另一個實現,RoomTrackingLiveData主要是用於Database相關的操作,這裏我們只分析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添加訂閱者

liveData添加訂閱者,主要是通過observer方法添加進去,需要注意的是第一個參數必須是LifecycleOwner類型,表示訂閱者自己本身也必須有一個狀態,在訂閱者死亡後LiveData就不在繼續給你同步消息了,添加observer的邏輯如下圖:
在這裏插入圖片描述
首先,在Activity裏面添加訂閱者到liveData,因爲Activity本身就實現了LifecycleOwner接口,所以第一個參數爲this即可,第二個就是Observer對象;然後就進入到LiveData類的observer裏面去,如下代碼:

public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
   如果添加進入的owner已經都是DESTROYED狀態,那麼久沒必要在添加進來了
   if (owner.getLifecycle().getCurrentState() == DESTROYED) {
       // ignore
       return;
   }
   內部封裝類,將owner和Observer參數封裝在一起
   LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
   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;
   }
   owner.getLifecycle().addObserver(wrapper);
}
LifecycleBoundObserver實現了LifecycleEventObserver,方便訂閱者將自己的狀態同步過來
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
        @NonNull
        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
            super(observer);
            mOwner = owner;
        }
        訂閱者那邊如果生命狀態發生變化會把狀態通知過來
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            如果訂閱者轉頭爲DESTROYED,那就把這個訂閱者從livedata中刪除掉
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            狀態通知下去,
            activeStateChanged(shouldBeActive());
        }
        這塊代碼主要作用是訂閱者的狀態由false變爲true的時候,要給他來一次事件發佈
		void activeStateChanged(boolean newActive) {
			如果狀態都一樣,那麼沒必要把數據在發佈給訂閱者
            if (newActive == mActive) {
                return;
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            /*省略部分代碼*/
            如果存活就把value發送給訂閱者
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }

mObservers.putIfAbsent 將訂閱者添加到mObservers裏面,mObservers是SafeIterableMap類型,就是一個雙鏈表數據結構,存儲元素類型爲Entry:

public V putIfAbsent(@NonNull K key, @NonNull V v) {
    Entry<K, V> entry = get(key);
    if (entry != null) {
        return entry.mValue;
    }
    put(key, v);
    return null;
}

protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
    Entry<K, V> newEntry = new Entry<>(key, v);
    mSize++;
    if (mEnd == null) {
        mStart = newEntry;
        mEnd = mStart;
        return newEntry;
    }
    mEnd.mNext = newEntry;
    newEntry.mPrevious = mEnd;
    mEnd = newEntry;
    return newEntry;

}

代碼很簡單,直接看就行;
最後在observer方法最後一句owner.getLifecycle().addObserver(wrapper),也就是會把這個wrapper添加到訂閱者(Activity)那邊去,爲什麼這麼做呢?主要是添加過去後,方便Activity生命週期變化,進行狀態同步過來


更新LiveData數據

在MutableLiveData中有set和post兩種方法更新,post可以在非主線程使用,而set必須在子線程使用,我們用post來看看:

protected void postValue(T value) {
    boolean postTask;
    多線程處理mPendingData,所以必須加鎖
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    postTask爲false,說明mPendingData已經有值,並且正在把值分發給訂閱者;
    所以這裏不需要再次分發,直接返回,只修改mPendingData即可
    if (!postTask) {
        return;
    }
    開始在主線程執行mPostValueRunnable
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

上述代碼主要是先獲取同步鎖,檢查mPendingData是否已經設置,更新mPendingData,如果已經改變,說明消息發佈任務已啓動,無須再次啓動,然後進入postToMainThread方法看看:

@Override
public void postToMainThread(Runnable runnable) {
    if (mMainHandler == null) {
        synchronized (mLock) {
            if (mMainHandler == null) {
            	獲取主線程的Looper,創建一個異步的Handler
                mMainHandler = createAsync(Looper.getMainLooper());
            }
        }
    }
    handler發送runnable任務
    mMainHandler.post(runnable);
}

這裏線程切換就是handler來實現的,需要了解Android handle機制看這裏
最後,再回頭看看這個Runnable是什麼任務?

private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
    Object newValue;
    寫入值和發送值不能同時處理,所以必須要用同一把鎖鎖住
    synchronized (mDataLock) {
    	把值拷貝到新的newValue去,同時要設置mPendingData爲NOT_SET,
    	方便下次值的寫入
        newValue = mPendingData;
        mPendingData = NOT_SET;
    }
    setValue((T) newValue);
}
};

@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    沒寫入一次值,要爲其賦一個版本號
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

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<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                這裏就是消息分發    
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

private void considerNotify(ObserverWrapper observer) {
	如果這個訂閱者mActive爲false,也就是小於STARTED狀態,就沒必要消息分發了
    if (!observer.mActive) {
        return;
    }
    這裏檢查的不是訂閱者,是訂閱者那邊的LifecycleOwner的狀態,這個狀態比上面的可靠
    並把狀態同步給訂閱者,此時訂閱者狀態是正確的,而且也沒必要去消息分發;
    這裏爲什麼要這麼做?是因爲訂閱者observer可能還不是最新的狀態,所以需要把LifecycleOwner
    同步給訂閱者,以免做無用的消息分發
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    這裏搞不懂,mLastVersion都是爲啥要這麼多,會出現大於的情況嗎,我覺得不會出現,
    因爲	mLastVersion都是mVersion賦值給他的,他肯定比mVersion小啊
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    執行onChanged方法,就是最初的Observer的回調函數
    observer.mObserver.onChanged((T) mData);
}

以上消息分發就完成了,做個小結:

  1. 注意post和set的區別,主線程和任意線程
  2. post會出現多線程共同使用mPendingData的情況,所以要加鎖,並且使用完後要mPendingData重置爲NOT_SET
  3. 最後就是在消息通知時要先判斷一下訂閱者狀態,小於STARTED不需要分發,因爲訂閱者狀態可能會有延遲,就把訂閱者所屬的LifecycleOwner的狀態給他同步過來,false也不往下發
  4. 最後更新版本號,然後執行onChanged

銷燬訂閱者

訂閱者自身狀態DESTROYED死亡後,需要將自己從LiveData中remove掉,主要發生在LiveData的內部類LifecycleBoundObserver中的onStateChanged方法裏面,因爲LifecycleBoundObserver實現了LifecycleEventObserver接口,在訂閱者那邊LifecycleOwner提前在LiveData的observer方法最後將LifecycleBoundObserver添加進去了,也就是添加到了LifecycleOwner的訂閱者集合,所以當LifecycleOwner狀態變化時,會將狀態同步給他的訂閱者,也就是LifecycleBoundObserver,當處於DESTROY時,就會將同步調用LifecycleBoundObserver的onStateChanged方法,方法如下:

public void onStateChanged(@NonNull LifecycleOwner source,
    @NonNull Lifecycle.Event event) {
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

@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);
}

上面的文字描述比較複雜,難理解,你要理解的是LifecycleBoundObserver是對LiveData的訂閱封裝類,LiveData添加了LifecycleBoundObserver,用於消息通知;而LifecycleOwner也添加了這個LifecycleBoundObserver,這邊添加是爲了生命狀態同步,需要配合Android Lifecycle疑問看看;大致簡圖如下:
在這裏插入圖片描述


總結

LiveData採用觀察者模式,一有數據更新時,會發布給訂閱者;與很好的與視圖解耦,也無須擔心內存泄漏的問題,除非LiveData本身持有其他的外部引用導致自身無法釋放;因爲在Activity這端,會實時的把自身狀態同步給LifecycleBoundObserver,以便在DESTROY狀態下,liveData會自動remove掉訂閱者

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章