androidx.activity.ComponentActivity Link to heading

设计架构:

+-----------------------------------------------------------------------------------------------------+
|androidx.activity.ComponentActivity(or Derived Class)                                                |
|                                                          onResume(new instance)                     |
|                                                              ^                                      |
|                                                              |                                      |
|              getViewModelStore()                         onStart(new instance)->getViewModelStore() |
|                     ^                                        ^                                      |
|                     |                                        |                                      |
|    +-------------------------------------------+         onCreate(new instance)->getViewModelStore()|    
|    |    androidx.lifecycle.ViewModelStore      |             ^                                      |
|    | (Single instance & Lazy initialization)   |             |                                      |
|    |     --------------------------------      |         onDestroy                                  |
|    |    |androidx.lifecycle.ViewModel - 1|     |             ^                                      |
|    |    |androidx.lifecycle.ViewModel - 2|     |             |                                      |
|    |    |androidx.lifecycle.ViewModel - 3|     |             |                                      |
|    |    |...                             |     |------>onRetainNonConfigurationInstance()           |   
|    |    |androidx.lifecycle.ViewModel - N|     |             ^                                      |
|    |     --------------------------------      |             |                                      |
|    |                                           |             |                                      |
|    |  clear: 1. Call clear() of each ViewModel.|           onStop                                   |
|    |   ^     2. Clear all viewModels           |             ^                                      |
|    +---|---------------------------------------+             |                                      |
|        |                                                     |                                      |
|        |                                                  onPause(due to configuration changed)     |
|        |                                                                                            |
|     onDestroy <---onStop <--- onPause(activity is done and should be closed.)                       |
+-----------------------------------------------------------------------------------------------------+

上面这张架构图描述了androidx.activity.ComponentActivity, androidx.lifecycle.ViewModelStoreandroidx.lifecycle.ViewModel之间的关系:每个androidx.activity.ComponentActivity的派生Activity都会持有1个androidx.lifecycle.ViewModelStore,只不过androidx.lifecycle.ViewModelStore直到getViewModelStore()调用时才会惰性创建1次(需要注意的是,创建这个androidx.lifecycle.ViewModelStore的前提有两个:当前Activity对象持有的mViewModelStorenull;如果当前Activity对象是由于配置改变(如旋转)重新创建的,而getViewModelStore()并没有在onCreateonStart时调用,则获取不到上次存储的androidx.lifecycle.ViewModelStore实例),这个androidx.lifecycle.ViewModelStore中会存储所有在这个派生Activity里创建的androidx.lifecycle.ViewModel。当当前Activity正常需要销毁的时候,会调用androidx.lifecycle.ViewModelStoreclear方法:先去调用所有的androidx.lifecycle.ViewModelclear方法以通知当前ViewModelStoreOwnerandroidx.activity.ComponentActivity/androidx.fragment.app.Fragment)需要销毁了,然后在清除调所有的androidx.lifecycle.ViewModel

//androidx.activity.ComponentActivity.java

package androidx.activity;

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {

    static final class NonConfigurationInstances {
        Object custom;
        ViewModelStore viewModelStore;
    }

    // Lazily recreated from NonConfigurationInstances by getViewModelStore()
    private ViewModelStore mViewModelStore;

    /**
     * Default constructor for ComponentActivity. All Activities must have a default constructor
     * for API 27 and lower devices or when using the default
     * {@link android.app.AppComponentFactory}.
     */
    public ComponentActivity() {
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });
    }

    /**
     * Retain all appropriate non-config state.  You can NOT
     * override this yourself!  Use a {@link androidx.lifecycle.ViewModel} if you want to
     * retain your own non config state.
     */
    @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }

        if (viewModelStore == null && custom == null) {
            return null;
        }

        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

    /**
     * Returns the {@link ViewModelStore} associated with this activity
     * <p>
     * Overriding this method is no longer supported and this method will be made
     * <code>final</code> in a future version of ComponentActivity.
     *
     * @return a {@code ViewModelStore}
     * @throws IllegalStateException if called before the Activity is attached to the Application
     * instance i.e., before onCreate()
     */
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
}

综上所述,下面列出几个的关键点:

  • 当你的Activity是androidx.activity.ComponentActivity的派生类,如果需要存储一些将由配置改变(比如旋转)而丢失的昂贵数据,推荐使用 androidx.lifecycle.ViewModel。这是因为androidx.activity.ComponentActivity重写了onRetainNonConfigurationInstance()这个方法并添加了final修饰符,所以不允许其派生类继续重写。当然你也可以使用onRetainCustomNonConfigurationInstancegetLastCustomNonConfigurationInstance这两个方法实现,但这两个方法都已经废弃,所以不推荐使用。
  • getViewModelStore()不能在onCreate()生命周期之前调用。
  • 如果当前Activity实例是由于配置变更(比如旋转)重新创建的,getViewModelStore()的调用除了不能在onCreate()生命周期之前调用,还不能在onStart之后调用,即只能在onCreateonStart这两个生命周期中调用。
  • 如果当前Activity实例由于配置变更(比如旋转)执行销毁流程,当销毁的时候,不移除所有存储的androidx.lifecycle.ViewModel
  • 如果当前Activity实例正常执行销毁流程,当销毁的时候,会调用所有androidx.lifecycle.ViewModelclear方法,然后在androidx.lifecycle.ViewModel的内部调用onCleared方法,这样我们就可以在我们自定义的androidx.lifecycle.ViewModelonCleared方法中执行资源释放,网络请求取消等操作。

androidx.fragment.app.Fragment Link to heading

设计架构:

+-----------------------------------------------------------------------------------------------------+
                 |androidx.fragment.app.Fragment(or Derived Class)|                                   |
                 +------------------------------------------------+                                   |
                                                                                                      |
    getViewModelStore()
            ^
            |
    +-------|-----------------------------------------------------------------------------------+
            |    |androidx.fragment.app.FragmentManager|                                        |
            |    +-------------------------------------+                                        |
            |                                                                                   |
    getViewModelStore(androidx.fragment.app.Fragment)
            ^
            |
    +-------|--------------------------------------------------------------------------------+
            |    |androidx.fragment.app.FragmentManagerViewModel|                            |
            |    +----------------------------------------------+                            |
            |                                                                                |
    getViewModelStore(androidx.fragment.app.Fragment)  
            ^
            |
        +---------------------------------------------------------------------------------+
        |         |mViewModelStores(HashMap<String, androidx.lifecycle.ViewModelStore>)|  |
        |         +--------------------------------------------------------------------+  |
        |                                                                                 |
        |  androidx.fragment.app.Fragment@1 => androidx.lifecycle.ViewModelStore@1        |
        |  androidx.fragment.app.Fragment@2 => androidx.lifecycle.ViewModelStore@2        |
        |  androidx.fragment.app.Fragment@3 => androidx.lifecycle.ViewModelStore@3        |
        |  ...                                                                            |
        |  androidx.fragment.app.Fragment@N => androidx.lifecycle.ViewModelStore@N        |
        |                                                                                 |
        +---------------------------------------------------------------------------------+

在梳理androidx.lifecycle.ViewModelandroidx.fragment.app.Fragment中的设计流程之前,我们需要先了解一些FragmentManager的知识:当我们创建了一个直接/间接继承自androidx.fragment.app.FragmentActivity的Activity并交给系统,然后系统开始实例化这个Activity的时候,同时也会初始化了一个FragmentManager(只不过这个FragmentManagerandroidx.fragment.app.FragmentHostCallback直接持有,而androidx.fragment.app.FragmentController又直接持有androidx.fragment.app.FragmentHostCallback, androidx.fragment.app.FragmentController又被androidx.fragment.app.FragmentActivity直接持有),所以直接在这个Activity中通过事务提交的Fragments都由这个FragmentManager直接管理,并且这些Fragment中持有的mFragmentManager也是这个FragmentManager。而在这些Fragment中创建的子Fragment由它的创建者Fragment(父Fragment)的mChildFragmentManager(在父Fragment实例化的时候初始化)负责管理。

img

每个FragmentManager持有一个androidx.fragment.app.FragmentManagerViewModel,由它负责管理这些Fragments(由这个FragmentManager直接管理)中使用的androidx.lifecycle.ViewModelStore

我们在Fragment中获取到的ViewModelStore来自于androidx.fragment.app.FragmentManagerViewModel,这是一个ViewModel,它内部维护了一个K-V容器用来存储每个Fragment对应的ViewModelStore。那这个FragmentManagerViewModel是怎么创建的呢?

// androidx.fragment.app.FragmentManager.java

package androidx.fragment.app;

public abstract class FragmentManager {

    private FragmentManagerViewModel mNonConfig;
    
    void attachController(@NonNull FragmentHostCallback<?> host,
            @NonNull FragmentContainer container, @Nullable final Fragment parent) {
        ...

        // Get the FragmentManagerViewModel
        if (parent != null) {
            mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
        } else if (host instanceof ViewModelStoreOwner) {
            ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
            mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
        } else {
            mNonConfig = new FragmentManagerViewModel(false);
        }
    }

    @NonNull
    private FragmentManagerViewModel getChildNonConfig(@NonNull Fragment f) {
        return mNonConfig.getChildNonConfig(f);
    }
}

创建FragmentManagerViewModel有三种情况:

  1. 第一种情况:

    ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
    mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
    

    这种情况发生在androidx.fragment.app.FragmentActivity执行到生命周期onCreate的时候,此时host会attach到FragmentManager,这样之后才可以用这个FragmentManager管理Fragments。由上述代码可知,ViewModelStore来自于host,这个host实现了ViewModelStoreOwner这个接口以提供ViewModelStore,然后我们通过将新创建的FragmentManagerViewModel存储到这个ViewModelStore中。

    // androidx.fragment.app.FragmentManagerViewModel.java
    
    package androidx.fragment.app;
    
    final class FragmentManagerViewModel extends ViewModel { 
        private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
            @NonNull
            @Override
            @SuppressWarnings("unchecked")
            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
                FragmentManagerViewModel viewModel = new FragmentManagerViewModel(true);
                return (T) viewModel;
            }
        }
    
        @NonNull
        static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
            ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
                    FACTORY);
            return viewModelProvider.get(FragmentManagerViewModel.class);
        }
    }
    

    现在我们只要知道host在哪,我们就知道FragmentManagerViewModel存储在哪:

    // androidx.fragment.app.FragmentActivity.java
    
    package androidx.fragment.app;
    
    public class FragmentActivity extends ComponentActivity implements
            ActivityCompat.OnRequestPermissionsResultCallback,
            ActivityCompat.RequestPermissionsRequestCodeValidator {
    
        final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    
        class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
                ViewModelStoreOwner,
                OnBackPressedDispatcherOwner {
            public HostCallbacks() {
                super(FragmentActivity.this /*fragmentActivity*/);
            }
    
            @NonNull
            @Override
            public ViewModelStore getViewModelStore() {
                return FragmentActivity.this.getViewModelStore();
            }
        }
    }
    

    很清楚了,FragmentActivity继承自ComponentActivity,所以FragmentManagerViewModel存储在这个Fragment的宿主Activity中。

  2. 第二种情况

    mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
    

    我们知道,一个Fragment包含两个FragmentManagermFragmentManagermChildFragmentManager,后者就是用来管理在这个Fragment中创建的所有子Fragment,当这个Fragment attach到host的时候,mChildFragmentManager会在父Fragment关联的FragmentManagerViewModel中的mChildNonConfigs创建一个新的FragmentManagerViewModel(key:父Fragment)供这个mChildFragmentManager所管理的所有Fragments使用。

    // androidx.fragment.app.Fragment
    
    package androidx.fragment.app;
    
    public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
        ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner {
    
        void performAttach() {
            mChildFragmentManager.attachController(mHost, new FragmentContainer() {
                @Override
                @Nullable
                public View onFindViewById(int id) {
                    if (mView == null) {
                        throw new IllegalStateException("Fragment " + this + " does not have a view");
                    }
                    return mView.findViewById(id);
                }
    
                @Override
                public boolean onHasView() {
                    return (mView != null);
                }
            }, this);
            mState = ATTACHED;
            mCalled = false;
            onAttach(mHost.getContext());
            if (!mCalled) {
                throw new SuperNotCalledException("Fragment " + this
                        + " did not call through to super.onAttach()");
            }
        }
    }
    

    这样意味这我们可以在androidx.fragment.app.FragmentActivityViewModelStore里存储的FragmentManagerViewModel通过mChildNonConfigsmViewModelStores直接或间接获取到附加到这个Activity上所有的Fragment和子Fragment的ViewModel

    img

  3. 第三种情况

    mNonConfig = new FragmentManagerViewModel(false);
    

    这种已经废弃,可以不用考虑。

androidx.lifecycle.ViewModel Link to heading

我们平时所使用的ViewModel都需要继承这个类,这个类设计的很简单,对于我们来说有用的方法只有一个:onCleared,要注意这个方法很重要,当我们的ViewModel需要被移除的时候,会调用这个方法,所以我们可以在这个方法对正在观察的数据去取消订阅,关闭正在加载的资源等。

ViewModel禁止持有一些如View/Activity/Fragment这些引用,想象一下旋转一个Activity的时候,如果ViewModel持有这个Activity的引用,导致这个Activity在需要被销毁的时候由于ViewModel的引用而导致无法被销毁,导致Activity内存泄漏。

ViewModel的存在也简化了FragmentFragment之间的通信:我们只需要定义一个用于Fragment之间共享的ViewModel,然后将它存储在这些Fragment的宿主Activity的ViewModelStore中,然后这些Fragment就都可以获取到这个Fragment,然后相互通信,不需要定义交互接口,不要在宿主Activity中处理过多的逻辑。

ViewModel也是官方推荐替换onRetainNonConfigurationInstance去保留所有适当的非配置状态(non-config state)的方法。