android生命週期神器--Lifecycle

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);
            }
         }
    
     }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章