android生命掌控組件LifeCycle

android JetPack組件之LifeCycle

在這裏插入圖片描述


簡介

Lifecycle組件是JetPack的核心組件之一,JetPack的其他許多組件都會用到Lifecycle這一組件,如ViewModel、LiveData等。LifeCycle是負責觀測Activity生命週期變化狀態,並同步給它的訂閱者,使訂閱者實時感知如Activity生命狀態,在正確的狀態做正確的事,如Activity的onDestroy時,切斷訂閱者與觀測目標的引用鏈,防止內存泄漏等問題


使用方法

我們只需要實現上圖訂閱者接口類,然後在Activity中調用getLifecycle()把訂閱類add進去即可。基礎類LifecycleObserver是一個空接口,如果實現該接口,我們可以任意寫一些方法,在方法頭部寫上註解@OnLifecycleEvent(Lifecycle.Event.ON_xxx)即可,xxx寫生命週期的各個方法,如DESTROY等,當觀測目標生命週期執行onDestroy時就會執行該方法;如下僞代碼:

1. 實現訂閱者
class Subcriber implements LifecycleObser{
	@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
	public void testOnCreate(){
		Log.i("i am running create");
	}
}

2. 將訂閱者添加到觀測類裏面去
class MyActivity extends AppCompatActivity{
	public void onCreate(savedInstanceState Bundle){
		/**
		getLifecycle爲Activity已實現的方法
		*/
		getLifecycle().addObserver(new Subcriber());
	}
}

訂閱者還有其他的三個接口如LifecycleEventObserver等,這三個接口已經聲明瞭方法了,我們實現這幾個接口時,只需要在方法內部,判斷方法參數Event事件,然後執行相應的邏輯即可,無須在寫註解事件了;
這裏提出一個問題,如果在Activity中,生命週期已經從onCreate走到了onResume,這時我們在onResume方法裏面才添加一個Subcriber,那麼上面的testOnCreate還會執行嗎?
不知道不要緊,繼續往下看


背後原理

帶着問題閱讀無疑是最好的閱讀,邊閱讀邊思考,這裏提出幾個問題:

  1. 觀測目標如何實時將自己的狀態同步給訂閱者 ?
  2. 衆多的訂閱者是如何管理、以及如何同步狀態的 ?
  3. 觀測目標執行完onDestroy如何處理這些訂閱者 ?

ComponentActivity

文章頂部的圖片,先看看觀測目標的ComponentActivity類,從它入手

public class ComponentActivity  extends androidx.core.app.ComponentActivity implements
        LifecycleOwner{
	private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);

	@NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }
}

從上代碼可以看出,對於ComponentActivity的生命週期監聽的類是一個LifecycleRegistry,他負責對生命週期的監聽。


LifecycleRegistry

瞭解添加訂閱者之前,先介紹幾個標誌量:
private State mState; 當前觀測目標狀態、
private int mAddingObserverCounter = 0; 大於0,說明添加訂閱者正在發生
private boolean mHandlingEvent = false; 觀測目標狀態變化了,正在同步給所有的訂閱者
private boolean mNewEventOccurred = false; 以上兩個至少有一個在發生
private ArrayList mParentStates = new ArrayList<>(); 臨時狀態棧,用於添加訂閱者時記錄

然後繼續看看這個如何添加訂閱者的:

public void addObserver(@NonNull LifecycleObserver observer) {
	State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
	對訂閱者再次封裝包裹,主要是給他添加一個狀態State,用於後續狀態同步及事件分發
	ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
	將訂閱者添加到自己的mObserverMap管理組織起來,後續有事件時從mObserverMap取出來分發事件
	mObserverMap是一個HashMap + 雙鏈表的結構,value用雙鏈表組織結構,start和end首尾節點
	ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
	如果之前已經添加過,就不做後續的工作直接返回,
	if (previous != null) {
	    return;
	}
	mLifecycleOwner爲當前LifecycleRegistry構造方法傳入的觀測目標的弱引用,
	如果弱引用都沒了,就說明觀測目標都不存在了
	LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
	if (lifecycleOwner == null) {
	    // it is null we should be destroyed. Fallback quickly
	    return;
	}
	mAddingObserverCounter > 0表示正在爲傳入的observer做同步操作,可能添加進來時,觀測目標
	的聲明週期走了好幾個了,要給他補上
	mHandlingEvent爲true表明聲明週期事件觸發了,正在給他下面的訂閱者進行事件分發
	boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
	獲取observer的前一個節點,與當前觀測目標對比,取小值
	State targetState = calculateTargetState(observer);
	mAddingObserverCounter++;
	mAddingObserverCounter > 0表示正在給當前observer補上他的生命週期
	狀態對比statefulObserver.mState.compareTo(targetState) < 0,這個說明當前observer狀態
	比現在狀態還小,他需要走upEvent事件
	while ((statefulObserver.mState.compareTo(targetState) < 0
	        && mObserverMap.contains(observer))) {
	    對當前狀態壓棧    
	    pushParentState(statefulObserver.mState);
	    給這個observer分發事件,upEvent是從獲取他的up事件,也就是從狀態切換到事件
	    statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
	    popParentState();
	    //再次選最小值,知道while不滿足,也就是和當前狀態相等
	    targetState = calculateTargetState(observer);
	}
	if (!isReentrance) {
	    // we do sync only on the top level.
	    sync();
	}
	mAddingObserverCounter--;
}
//訂閱者封裝包裹類
static class ObserverWithState {
	State mState;
	LifecycleEventObserver mLifecycleObserver;
	
	ObserverWithState(LifecycleObserver observer, State initialState) {
	  lifecycleEventObserver將其轉換爲LifecycleEventObserver類型
	  mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
	  mState = initialState;
	}
	
	void dispatchEvent(LifecycleOwner owner, Event event) {
	  State newState = getStateAfter(event);
	  mState = min(mState, newState);
	  這裏事件分發
	  mLifecycleObserver.onStateChanged(owner, event);
	  mState = newState;
	}
}
計算它前一個Observer和當前觀測目標的聲明週期狀態,取最小值
private State calculateTargetState(LifecycleObserver observer) {
	ceil取他前面的一個observer節點
	Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
	
	State siblingState = previous != null ? previous.getValue().mState : null;
	mParentStates是臨時壓棧的狀態,也是在observer前面一個
	State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
	        : null;
	返回最小
	return min(min(mState, siblingState), parentState);
}

以上代碼,主要完成以下工作:

  1. 將訂閱者LifeCycleObserver封裝爲ObserverWithState類,包含一個狀態變量和統一的事件分發方法
  2. 將ObserverWithState添加到自己的mObserverMap中去,mObserverMap爲FastSafeIterableMap類型,是一個HashMap+雙鏈表結構
  3. 檢查觀測目標與這個LifeCycleObserver狀態,如果不同,要同步一下LifeCycleObserver到現在的狀態

對訂閱者的數據結構管理

在LifecycleRegistry中,mObserverMap是管理訂閱者FastSafeIterableMap<LifecycleObserver, ObserverWithState>的類,這個類的結構是HashMap+雙鏈表,mObserverMap是FastSafeIterableMap類型,看看他的結構體如何:

public class FastSafeIterableMap<K, V> extends SafeIterableMap<K, V> {
	private HashMap<K, Entry<K, V>> mHashMap = new HashMap<>();
	public V putIfAbsent(@NonNull K key, @NonNull V v) {
		調用父類的get檢查是否已經添加過
        Entry<K, V> current = get(key);
        if (current != null) {
            return current.mValue;
        }
        在加入到HashMap中去
        mHashMap.put(key, put(key, v));
        return null;
    }
}

public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {
 	Entry<K, V> mStart;
    private Entry<K, V> mEnd;
    遍歷查找是否有k的value
	protected Entry<K, V> get(K k) {
        Entry<K, V> currentNode = mStart;
        while (currentNode != null) {
            if (currentNode.mKey.equals(k)) {
                break;
            }
            currentNode = currentNode.mNext;
        }
        return currentNode;
    }
    新來的數據添加到mEnd之後,所以start是最新添加的,end是最後添加
	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;

    }
    原始的存儲element,多了上下兩個指向變量
	static class Entry<K, V> implements Map.Entry<K, V> {
        @NonNull
        final K mKey;
        @NonNull
        final V mValue;
        Entry<K, V> mNext;
        Entry<K, V> mPrevious;
     }
}

小結:
很多細節寫到了代碼註釋裏面去了,但是這裏爲什麼要使用HashMap+雙鏈表呢?只用其中一個不行嗎?答案肯定是可以的,但是爲了效率問題,在同步訂閱者狀態時,需要不停的檢測是否contains(observer),用hashMap效率快點,而隊列則要全部遍歷


生命狀態同步

Lifecycle將生命週期劃分爲 狀態事件 來處理,如下枚舉:

public enum Event {
        ON_CREATE,
        ON_START,
        ON_RESUME,
        ON_PAUSE,
        ON_STOP,
        ON_DESTROY,
        ON_ANY  //能匹配任何狀態
    }
public enum State {
        DESTROYED,
        INITIALIZED,
        CREATED,
        RESUMED;
        public boolean isAtLeast(@NonNull State state) {
            return compareTo(state) >= 0;
        }
    }

而且每個狀態執行了不同的方法會變成另一個狀態,狀態與事件的切換圖如下:
在這裏插入圖片描述
在LifecycleRegistry中,將狀態同步到訂閱者時,就是根據上面圖來對比執行的;假如某個訂閱者A的狀態是INITIALIZED,而觀測目標B現在是CREATED狀態,說明A比B的狀態小,說明是上面的事件,對應代碼就是upEvent方法,返回ON_CREATE事件,這個時候就把ON_CREATE事件同步給A,如下代碼:

private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                    + "garbage collected. It is too late to change lifecycle state.");
        }
        while (!isSynced()) {
            mNewEventOccurred = false;
            如果最早的訂閱者比觀測目標大,說明是downEvent事件,就倒序遍歷backwardPass
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
            同上
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
}
private void backwardPass(LifecycleOwner lifecycleOwner) {
	遞減iterator
	Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
	     mObserverMap.descendingIterator();
	開始遍歷,而且沒有新事件狀態下來
	while (descendingIterator.hasNext() && !mNewEventOccurred) {
		Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
		ObserverWithState observer = entry.getValue();
		取出訂閱者ObserverWithState
		while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
		        && mObserverMap.contains(entry.getKey()))) {
		    獲取狀態的down事件,狀態 --> 事件    
		    Event event = downEvent(observer.mState);
		    pushParentState(getStateAfter(event));
		    將event分發到observer
		    observer.dispatchEvent(lifecycleOwner, event);
		    popParentState();
		}
	}
}

小結:
重點在於理解狀態事件遷移圖,就可以理解代碼是如何將狀態切換的,以及如何分發下去;sync方法的意思就是:

  1. 首先對比訂閱者集合中首尾節點狀態是否一致,並且和觀測目標當前是否一致,不一致說明需要進行狀態同步
  2. 先判斷最早的訂閱者節點是否小於觀測目標狀態,小於就從訂閱者集合倒序遍歷進行狀態同步,只有小於觀測目標狀態纔會同步backwardPass
  3. 然後判斷最後的節點狀態是否大於觀測目標狀態,大於就正序遍歷forwardPass所有訂閱者節點,大於就進行事件分發
  4. 走完一遍後,在執行步驟1,如果狀態還不一致,在執行2和3,因爲有的訂閱者可能和觀測目標之間相隔1個以上的狀態,所以需要再次執行while循環
  5. 最後的效果是,所有訂閱者狀態一步一步向觀測目標的狀態靠攏,而不是一個訂閱者連續執行兩個狀態事件

Activity的生命週期事件如何傳遞進入LifecycleRegistry

簡單來說,只需要在Activity的各個生命週期調用getLifecycle.handleLifecycleEvent()即把生命狀態傳遞進去了,遺憾的是我在ComponentActivity類裏面並沒有看到生命週期去調用handleLifecycleEvent方法,很奇怪。找遍他的子類也沒有,但是訂閱者卻能響應各個生命週期方法,肯定是哪裏調用了的,只是我沒有找到,如果讀者的你找到,還望分享一下!


總結

Lifecycle是Jetpack的核心組件之一,使用很方便,能讓你的訂閱者時刻感知目標的狀態;重點要理解Lifecycle如何管理衆多的訂閱者,生命狀態如何在訂閱者之間同步,以及狀態遷移;看代碼的你可能發現了這個問題,LifecycleRegistry添加訂閱者後,並沒有在OnDestroy後把這些訂閱者remove掉,會不會導致內存泄漏,答案是否定的,因爲LifecycleRegistry構造方法傳遞進去的是弱引用,不影響GC對Activity的垃圾回收

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