文章目錄
android生命週期神器–Lifecycle
- 官方文檔: https://developer.android.google.cn/topic/libraries/architecture/lifecycle#java
繼承關係
- 首先梳理下類的繼承關係和相應的接口
AppCompatActivity(AppCompatCallback)-->FragmentActivity(ViewModelStoreOwner)--> ComponentActivity(LifecycleOwner)-->Activity
LifecycleRegistryOwner(interface)-->LifecycleOwner(interface)
LifecycleRegistry-->Lifecycle(abstract)
Lifecycle只是抽象類,LifecycleRegistry是Lifecycle的唯一子類,實現了其抽象方法
問題
- 下面以提問的方式對Lifecycle進行介紹
生命週期通知大部分是在Fragment中觸發的,那沒有Fragment的Activity呢?它的生命週期通知是啥時觸發的
-
一開始我也很奇怪,生命週期事件大多都是在Fragment中發出的,那Activity呢?後面才知道爲了降低侵入性,增加了一個ReportFragment,ComponentActivity在onCreate時就執行了ReportFragment.injectIfNeededIn(this);,從而將生命週期轉移到Fragment,由Fragment進行觸發了
-
ReportFragment的生命週期會通知到其對應Activity的LifecycleRegistry,再由LifecycleRegistry通知到觀察者
public class ComponentActivity extends Activity implements LifecycleOwner, KeyEventDispatcher.Component { ... @Override @SuppressWarnings("RestrictedApi") protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); /////////////////////重點////////////////////////// //關鍵就是這一步判斷,它會添加ReportFragment /////////////////////重點////////////////////////// ReportFragment.injectIfNeededIn(this); } ... }
public class ReportFragment extends Fragment { private static final String REPORT_FRAGMENT_TAG = "androidx.lifecycle" + ".LifecycleDispatcher.report_fragment_tag"; public static void injectIfNeededIn(Activity activity) { // ProcessLifecycleOwner should always correctly work and some activities may not extend // FragmentActivity from support lib, so we use framework fragments for activities android.app.FragmentManager manager = activity.getFragmentManager(); if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) { manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit(); // Hopefully, we are the first to make a transaction. manager.executePendingTransactions(); } } }
爲啥要用ViewModelProviders去創建ViewModel的實例
-
首先說下原因,這是爲了在適當的時機去銷燬ViewModel所佔用的資源,同時也爲了實現多實例共享同一個ViewModel
-
接着就說明是如何做到以上兩點的,請看下面分析
-
爲了更直觀些,現把Activity的繼承關係梳理下,其中括號表示接口
AppCompatActivity–>FragmentActivity–>ComponentActivity(LifecycleOwner,ViewModelStoreOwner)–>Activity
-
爲了讓Activity自動管理ViewModel,我們就需要利用
ViewModelProviders.of(this).get(XXViewModel.class);
得到ViewModel對象 -
至於爲啥要用這個去創建ViewModel,是因爲其在內部通過this對象拿到了ViewModelStore對象,這個ViewModelStore就是保存了當前對象所持有的ViewModel(說白了ViewModelStore就是一個HaspMap的簡單封裝而已,用於存儲ViewModel),拿到ViewModelStore對象就可以通過XXViewModel.class這個key去得到ViewModel對象,這時ViewModelStore不一定存在此key對應的ViewModel對象,如果沒有那麼就通過KeyedFactory去創建一個了,再把剛創建的塞回ViewModelStore。
-
這樣跟我們單獨new一個ViewModel對象有啥區別呢?我們單獨new的對象並沒有加入到ViewModelStore裏管理,因此ViewModel是獨立的,一個實例對象裏的viewModel無法被其他實例訪問到,假如我們的場景就是這樣的,ViewModel並不需要在多個實例中共享一個,那麼簡單new一個也沒啥問題;假如我們需要在多個實例中共享同一個ViewModel,那麼通過ViewModelProviders來獲取ViewModel就是比較好的辦法了;
-
那麼什麼場景下有共享ViewModel的需求呢,比如你想在Activity下的多個Fragment之間共用一個ViewModel,那麼利用ViewModelProviders就是最方便快捷的選擇。
-
通過ViewModelProviders會將ViewModel存儲進ViewmodelStore,ViewmodelStore由於ViewModelStoreOwner接口的原因可以被生命週期獲取到進而進行管理,也就是會在適當的時機幫你銷燬viewmodel的資源,同時有了ViewmodelStore的管理也能輕而易舉實現多個Fragment共享同一個Viewmodel,顯然自己手動new一個Viewmodel是沒有這些好處的
-
因此總結下來就是,Viewmodel最好不要手動創建,交給ViewModelProviders去管理,那麼事情會變得簡單而且不易出錯。
-
當然,如果你的Viewmodel非常簡單,既沒有共享的需求,也沒什麼資源需要特別釋放(即不需要在ViewModel.onCleared裏操作什麼),那麼手動創建也是可以的。
-
如果你想說自己手動創建viewmodel後扔進viewmodelstore裏,不好意思,辦不到,因爲目前Viewmodelstore的put方法並不是public的(反射不推薦),因此乖乖用ViewModelProviders吧
爲啥說ViewModel放入Viewmodelstore後在Activity Destroy後會自動釋放資源
- 原因就在ComponentActivity裏查找
- 從代碼中我們很清楚看到ComponentActivity添加了一個觀察者,當銷燬時就會調用clear方法
爲啥說在ViewModel不能持有Activity或Fragment的引用
- 因爲viewmodel的生命週期比activity長,如果activity configuration發生變化(比如屏幕旋轉),新的實例會重新使用已存在的viewmodel,試想一下,如果viewmodel持有舊activity的引用,那麼就會導致舊activity無法被回收,造成內存泄漏
- 那麼爲何說ViewModel的生命週期比activity長呢,因爲ViewModel是可以給多個實例共用的,這就導致ViewModel的生命週期大於引用它的多實例中生命週期最短的那一個,簡單點來說,就是ViewModel被一個存活10秒和20秒的實例引用,那麼ViewModel就存活20秒(20>10)
爲啥說LiveData在Activity或Fragment不可見時不會去通知觀察者
- 我們知道在使用LiveData添加觀察者時需要添加LifecycleOwner和Observer,添加的這兩個對象實際上會被包裝在LifecycleBoundObserver中,LifecycleBoundObserver.shouldBeActive就是根據當前狀態判斷是否需要通知觀察者,而LiveData決定是否通知觀察者就是在LiveData.considerNotify(ObserverWrapper observer)方法中處理的,可想而知,此方法中就是用到了LifecycleBoundObserver.shouldBeActive()作出決定的
- 這裏說明一下,LifecycleBoundObserver是LiveData的內部類,LifecycleBoundObserver繼承了抽象類ObserverWrapper
- LiveData部分代碼如下,主要看重點標記的代碼
public abstract class LiveData<T> { private void considerNotify(ObserverWrapper observer) { if (!observer.mActive) { return; } /////////////////////重點////////////////////////// //關鍵就是這一步判斷,如果不可見直接就返回了,不會去通知觀察者 /////////////////////重點////////////////////////// if (!observer.shouldBeActive()) { observer.activeStateChanged(false); return; } if (observer.mLastVersion >= mVersion) { return; } observer.mLastVersion = mVersion; //noinspection unchecked observer.mObserver.onChanged((T) mData); } class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver { @NonNull final LifecycleOwner mOwner; LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) { super(observer); mOwner = owner; } /////////////////////重點////////////////////////// //關鍵就是這一步判斷,最新狀態如果是STARTED纔會去通知觀察者 /////////////////////重點////////////////////////// @Override boolean shouldBeActive() { return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED); } } }