Jetpack-ViewModel源碼解析

ViewModel源碼解析

源碼版本:

  • ViewModel:2.4.0
  • Android:31
  • androidx.activity:activity:1.4.0
  • androidx.fragment:fragment:1.4.0

需會使用:Lifecycle

導(dǎo)航:

使用

聲明ViewModel

class MyViewModel : ViewModel() {

    override fun onCleared() {
        super.onCleared()
    }
}

獲取ViewModel

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // 獲取ViewModel
        val model = ViewModelProvider(this).get(MyViewModel::class.java)
        // observe
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI
        })
    }
}

ViewModel生命周期

enter image description here

源碼

聲明ViewModel

ViewModel類

public abstract class ViewModel {
    // 標(biāo)簽集合
    @Nullable
    private final Map<String, Object> mBagOfTags = new HashMap<>();
    // 標(biāo)記是否是已清除
    private volatile boolean mCleared = false;

    // 當(dāng)ViewModel被清除時調(diào)用
    protected void onCleared() {
    }

    @MainThread
    final void clear() {
        mCleared = true;
        if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    // see comment for the similar call in setTagIfAbsent
                    closeWithRuntimeException(value);
                }
            }
        }
        onCleared();
    }

    // 添加數(shù)據(jù)key侥衬、value涮拗,如果key的值已經(jīng)存在,則返回已存在的值饰剥,否則添加新的值。
    // 并判斷如果ViewModel是已被清除的摧阅,則返回的值如果是Closeable汰蓉,就會調(diào)用close方法釋放。即ViewModel已經(jīng)被清除棒卷,再添加新的顾孽,則也會釋放。
    @SuppressWarnings("unchecked")
    <T> T setTagIfAbsent(String key, T newValue) {
        T previous;
        synchronized (mBagOfTags) {
            previous = (T) mBagOfTags.get(key);
            if (previous == null) {
                mBagOfTags.put(key, newValue);
            }
        }
        T result = previous == null ? newValue : previous;
        if (mCleared) {

            closeWithRuntimeException(result);
        }
        return result;
    }

    // 獲取被添加的數(shù)據(jù)
    <T> T getTag(String key) {
        if (mBagOfTags == null) {
            return null;
        }
        synchronized (mBagOfTags) {
            return (T) mBagOfTags.get(key);
        }
    }

    private static void closeWithRuntimeException(Object obj) {
        if (obj instanceof Closeable) {
            // 是Closeable子類比规,則調(diào)用close關(guān)閉若厚。
            try {
                ((Closeable) obj).close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

ViewModel被清除的時候,會清空Tag并調(diào)用onCleared方法通知ViewModel被清除蜒什。

獲取ViewModel

使用

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // 獲取ViewModel
        val model = ViewModelProvider(this).get(MyViewModel::class.java)
        // observe
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI
        })
    }
}

獲取ViewModel测秸,首先需要創(chuàng)建ViewModelProvider,然后再調(diào)用其get方法獲取,我們先來看一下ViewModelProvider對象是如果創(chuàng)建的霎冯,然后再看get方法是如果獲取的铃拇。

ViewModelProvider構(gòu)造方法

ViewModelProvider構(gòu)造方法

public open class ViewModelProvider(
    private val store: ViewModelStore,
    private val factory: Factory
) {
    public constructor(
        owner: ViewModelStoreOwner
    ) : this(owner.viewModelStore, defaultFactory(owner))

    
    public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
        owner.viewModelStore,
        factory
    )  
}

ViewModelProviderViewModel提供者,創(chuàng)建它需要ViewModelStoreViewModelProvider.Factory沈撞,而ViewModelStore又可以從ViewModelStoreOwner中獲取慷荔,我們分別來看下這幾個類。

ViewModelStore

ViewModelStore類

public class ViewModelStore {

    // ViewModel集合
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
TestViewModel
    // 保存ViewModel缠俺,如果key已經(jīng)存在显晶,則值進行覆蓋,之前的ViewModel則調(diào)用onCleared清空邏輯壹士。
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    // 獲取ViewModel
    final ViewModel get(String key) {
        return mMap.get(key);
    }

    // 獲取所有的key
    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    // 清除內(nèi)部存儲并通知ViewModels它們不再使用磷雇。
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

ViewModelProviderViewModel商店,它是用來存儲獲取ViewModel的躏救,是使用HashMap來實現(xiàn)的唯笙。其clear方法會清除內(nèi)部存儲并通知ViewModels它們不再使用。

ViewModelStoreOwner

ViewModelStoreOwner類

public interface ViewModelStoreOwner {

    @NonNull
    ViewModelStore getViewModelStore();
}

ViewModelStoreOwnerViewModelStore的持有者落剪,通過它的子類可以獲取到ViewModelStore睁本。androidxActivityFragment都已經(jīng)實現(xiàn)了ViewModelStoreOwner,我們分別看一下具體實現(xiàn)忠怖。

Activity

androidx.activity.ComponentActivity類

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        ContextAware,
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner,
        ActivityResultRegistryOwner,
        ActivityResultCaller {
        
    private ViewModelStore mViewModelStore;
    
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        if (getApplication() == null) {
            // 不能在onCreate調(diào)用之前獲取ViewModel
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        // 確保ViewModelStore
        ensureViewModelStore();
        // 返回ViewModelStore
        return mViewModelStore;
    }
    
    @SuppressWarnings("WeakerAccess") /* synthetic access */
    void ensureViewModelStore() {
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // 從 NonConfigurationInstances 中恢復(fù)ViewModelStore
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                // mViewModelStore為空呢堰,則創(chuàng)建。
                mViewModelStore = new ViewModelStore();
            }
        }
    }
    
}

androidx Activity獲取ViewModelStore凡泣,先從 NonConfigurationInstances 中恢復(fù)ViewModelStore(確保Activity重建后還能獲取到之前的ViewModelStore枉疼,具體分析看下面ViewModel是如何保持不變的?)鞋拟,如果還是沒有骂维,則進行創(chuàng)建。

說明:

  1. androidx Activity不能在onCreate調(diào)用之前獲取ViewModel贺纲。

Fragment

androidx.fragment.app.Fragment類

public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
        ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner,
        ActivityResultCaller {
        
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        if (mFragmentManager == null) {
            // 不能從detached的Fragment訪問ViewModels
            throw new IllegalStateException("Can't access ViewModels from detached fragment");
        }
        if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
            // 當(dāng)使用setMaxLifecycle(INITIALIZED)時航闺,不支持在Fragment到達onCreate()之前調(diào)用getViewModelStore()
            throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
                    + "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
                    + "supported");
        }
        return mFragmentManager.getViewModelStore(this);
    }
}

FragmentManager --> getViewModelStore方法

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}

FragmentManagerViewModel --> getViewModelStore方法

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}

androidx Fragment獲取ViewModelStore,先獲取到 FragmentManagerViewModel(確保Fragment重建后還能獲取到之前的ViewModelStore猴誊,具體分析看下面ViewModel是如何保持不變的潦刃?),然后再從其mViewModelStores中獲取懈叹,如果沒有乖杠,則進行創(chuàng)建。

說明:

  1. androidx Fragment不能在onDetach調(diào)用之后獲取ViewModel澄成。

ViewModelProvider.Factory

ViewModelProvider.Factory類

public interface Factory {

    // 創(chuàng)建給定ViewModel Class的新實例胧洒。
    @NonNull
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}

ViewModelProvider.FactoryViewModel的創(chuàng)建工廠畏吓,此Factory通過ViewModel類的class,創(chuàng)建ViewModel實例卫漫。我們分別來看一下它的子類KeyedFactory菲饼、NewInstanceFactoryAndroidViewModelFactory汛兜。

ViewModelProvider.KeyedFactory

ViewModelProvider.KeyedFactory類

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public abstract class KeyedFactory : OnRequeryFactory(), Factory {

    public abstract fun <T : ViewModel> create(
        key: String,
        modelClass: Class<T>
    ): T

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        throw UnsupportedOperationException(
            "create(String, Class<?>) must be called on implementations of KeyedFactory"
        )
    }
}

KeyedFactoryFactory 的抽象子類巴粪,重寫了create(Class<?>)方法通今,并且KeyedFactory子類必須重寫create( Class<?>)方法并應(yīng)該調(diào)用其create(String, Class<?>)方法粥谬。

ViewModelProvider.NewInstanceFactory

ViewModelProvider.NewInstanceFactory類

public open class NewInstanceFactory : Factory {
    @Suppress("DocumentExceptions")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return try {
            // 通過反射獲取實例
            modelClass.newInstance()
        } catch (e: InstantiationException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        } catch (e: IllegalAccessException) {
            throw RuntimeException("Cannot create an instance of $modelClass", e)
        }
    }

    public companion object {
        private var sInstance: NewInstanceFactory? = null

        // 單例 NewInstanceFactory
        @JvmStatic
        public val instance: NewInstanceFactory
            @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
            get() {
                if (sInstance == null) {
                    sInstance = NewInstanceFactory()
                }
                return sInstance!!
            }
    }
}

NewInstanceFactoryFactory 的子類,實現(xiàn)了create(Class<?>)方法辫塌,通過ViewModel類的class漏策,無參反射創(chuàng)建ViewModel實例。

說明:

  1. 使用NewInstanceFactory創(chuàng)建臼氨,此ViewModel必須有無參的且不是私有的構(gòu)造方法掺喻。
  • 可以處理如下ViewModel
    • class MyViewModel : ViewModel()
  1. NewInstanceFactory.instance為全局單例NewInstanceFactory,防止了每次創(chuàng)建工廠储矩,優(yōu)化了性能感耙。

ViewModelProvider.AndroidViewModelFactory

ViewModelProvider.AndroidViewModelFactory類

public open class AndroidViewModelFactory(
    private val application: Application
) : NewInstanceFactory() {
    @Suppress("DocumentExceptions")
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
            try {
                // 此ViewModel為AndroidViewModel的子類,則傳入Application并創(chuàng)建持隧。
                modelClass.getConstructor(Application::class.java).newInstance(application)
            } catch (e: NoSuchMethodException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: IllegalAccessException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: InstantiationException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            } catch (e: InvocationTargetException) {
                throw RuntimeException("Cannot create an instance of $modelClass", e)
            }
        } else super.create(modelClass) // 否則即硼,則執(zhí)行父類的反射創(chuàng)建。
    }

    public companion object {
        // 獲取默認工廠屡拨,如果owner有默認工廠則用owner的只酥,否則用NewInstanceFactory工廠(反射創(chuàng)建)。
        internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
            if (owner is HasDefaultViewModelProviderFactory)
                owner.defaultViewModelProviderFactory else instance

        // 獲取的默認Key
        internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"

        private var sInstance: AndroidViewModelFactory? = null
        
        // 單例 AndroidViewModelFactory
        @JvmStatic
        public fun getInstance(application: Application): AndroidViewModelFactory {
            if (sInstance == null) {
                sInstance = AndroidViewModelFactory(application)
            }
            return sInstance!!
        }
    }
}

AndroidViewModelFactoryNewInstanceFactory 的子類呀狼,重寫了create(Class<?>)方法裂允,通過ViewModel類的class判斷,如果此ViewModelAndroidViewModel的子類哥艇,則傳入Application反射創(chuàng)建绝编,否則走父類邏輯無參反射創(chuàng)建ViewModel實例。

說明:

  1. 使用AndroidViewModelFactory創(chuàng)建貌踏,如果此ViewModelAndroidViewModel子類十饥,必須有一參的且是Application不是私有的構(gòu)造方法(不能無參);否則必須有無參的且不是私有的構(gòu)造方法(不能有參)哩俭。
  • 可以處理如下ViewModel
    • class MyViewModel : ViewModel()
    • class MyViewModel(application: Application) : AndroidViewModel(application)
  1. AndroidViewModelFactory.getInstance為全局單例AndroidViewModelFactory绷跑,防止了每次創(chuàng)建工廠,優(yōu)化了性能凡资。

defaultFactory方法為獲取默認工廠砸捏,如果ViewModelStoreOwner子類也實現(xiàn)了HasDefaultViewModelProviderFactory谬运,則用其提供的工廠,否則用NewInstanceFactory工廠(創(chuàng)建無參ViewModel)垦藏。

HasDefaultViewModelProviderFactory

HasDefaultViewModelProviderFactory類

public interface HasDefaultViewModelProviderFactory {
    
    // 獲取默認Factory
    @NonNull
    ViewModelProvider.Factory getDefaultViewModelProviderFactory();
}

HasDefaultViewModelProviderFactory為標(biāo)記可以獲取到默認Factory梆暖。androidxActivityFragment都已經(jīng)實現(xiàn)了HasDefaultViewModelProviderFactory,我們來分別看一下它們的具體實現(xiàn)掂骏。

Activity

androidx.activity.ComponentActivity類

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        ContextAware,
        LifecycleOwner,
        ViewModelStoreOwner,
        HasDefaultViewModelProviderFactory,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner,
        ActivityResultRegistryOwner,
        ActivityResultCaller {
        
    private ViewModelProvider.Factory mDefaultFactory;
    
    @NonNull
    @Override
    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        if (getApplication() == null) {
            // 不能在onCreate調(diào)用之前獲取ViewModel
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mDefaultFactory == null) {
            // 默認工廠為空轰驳,則進行創(chuàng)建SavedStateViewModelFactory,會把Application弟灼、當(dāng)前頁面?zhèn)魅氲膮?shù)级解,傳入到構(gòu)造方法中。
            mDefaultFactory = new SavedStateViewModelFactory(
                    getApplication(),
                    this,
                    getIntent() != null ? getIntent().getExtras() : null);
        }
        return mDefaultFactory;
    }
    
}

Fragment

androidx.fragment.app.Fragment類

public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
        ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner,
        ActivityResultCaller {
        
    ViewModelProvider.Factory mDefaultFactory;

    @NonNull
    @Override
    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        if (mFragmentManager == null) {
               // 不能從detached的Fragment訪問ViewModels
            throw new IllegalStateException("Can't access ViewModels from detached fragment");
        }
        if (mDefaultFactory == null) {
             // 默認工廠為空田绑,則進行創(chuàng)建SavedStateViewModelFactory勤哗,會把Application、當(dāng)前頁面?zhèn)魅氲膮?shù)掩驱,傳入到構(gòu)造方法中芒划。
            Application application = null;
            Context appContext = requireContext().getApplicationContext();
            while (appContext instanceof ContextWrapper) {
                if (appContext instanceof Application) {
                    application = (Application) appContext;
                    break;
                }
                appContext = ((ContextWrapper) appContext).getBaseContext();
            }
            if (application == null && FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                Log.d(FragmentManager.TAG, "Could not find Application instance from "
                        + "Context " + requireContext().getApplicationContext() + ", you will "
                        + "not be able to use AndroidViewModel with the default "
                        + "ViewModelProvider.Factory");
            }
            // 創(chuàng)建SavedStateViewModelFactory
            mDefaultFactory = new SavedStateViewModelFactory(
                    application,
                    this,
                    getArguments());
        }
        return mDefaultFactory;
    }
}

androidxActivityFragment的實現(xiàn)相同,都是創(chuàng)建SavedStateViewModelFactory并會把Application欧穴、當(dāng)前頁面傳入的參數(shù)民逼,傳入到構(gòu)造方法中,我們來看一下SavedStateViewModelFactory涮帘。

SavedStateViewModelFactory

SavedStateViewModelFactory類

public final class SavedStateViewModelFactory extends ViewModelProvider.KeyedFactory {
    private final Application mApplication;
    private final ViewModelProvider.Factory mFactory;
    private final Bundle mDefaultArgs;
    private final Lifecycle mLifecycle;
    private final SavedStateRegistry mSavedStateRegistry;

    // 構(gòu)造方法拼苍,未傳默認參數(shù)
    public SavedStateViewModelFactory(@Nullable  Application application,
            @NonNull SavedStateRegistryOwner owner) {
        this(application, owner, null);
    }
    
    // 構(gòu)造方法,傳了默認參數(shù)
    @SuppressLint("LambdaLast")
    public SavedStateViewModelFactory(@Nullable Application application,
            @NonNull SavedStateRegistryOwner owner,
            @Nullable Bundle defaultArgs) {
        mSavedStateRegistry = owner.getSavedStateRegistry();
        mLifecycle = owner.getLifecycle();
        mDefaultArgs = defaultArgs;
        mApplication = application;
        mFactory = application != null
                ? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
                : ViewModelProvider.NewInstanceFactory.getInstance();
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        // 是否是AndroidViewModel子類
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if (isAndroidViewModel && mApplication != null) {
            // 是AndroidViewModel子類焚辅,獲取(Application, SavedStateHandle)簽名的構(gòu)造方法
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            // 不是AndroidViewModel子類映屋,獲取(SavedStateHandle)簽名的構(gòu)造方法
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }

        if (constructor == null) {
            // 沒有獲取到,則說明是沒用SavedStateHandle的構(gòu)造方法同蜻,則直接用mFactory處理棚点。
            return mFactory.create(modelClass);
        }

        // 以下為需要SavedStateHandle
        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if (isAndroidViewModel && mApplication != null) {
                // 反射創(chuàng)建(Application, SavedStateHandle)簽名的構(gòu)造方法,并傳入SavedStateHandle湾蔓。
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                // 反射創(chuàng)建(SavedStateHandle)簽名的構(gòu)造方法瘫析,并傳入SavedStateHandle。
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            // 返回ViewModel
            return viewmodel;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("An exception happened in constructor of "
                    + modelClass, e.getCause());
        }
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        // 使用類名作為key默责,創(chuàng)建ViewModemLastNonConfigurationInstancesl贬循。
        return create(canonicalName, modelClass);
    }
    
    // (Application, SavedStateHandle)簽名
    private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class[]{Application.class,
            SavedStateHandle.class};
    // (SavedStateHandle)簽名
    private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class[]{SavedStateHandle.class};

    // 找到對應(yīng)簽名的構(gòu)造方法,沒有返回null桃序。
    @SuppressWarnings("unchecked")
    private static <T> Constructor<T> findMatchingConstructor(Class<T> modelClass,
            Class<?>[] signature) {
        for (Constructor<?> constructor : modelClass.getConstructors()) {
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            if (Arrays.equals(signature, parameterTypes)) {
                return (Constructor<T>) constructor;
            }
        }
        return null;
    }

    /**
     * @hide
     */
    @Override
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public void onRequery(@NonNull ViewModel viewModel) {
        attachHandleIfNeeded(viewModel, mSavedStateRegistry, mLifecycle);
    }
}

androidxActivityFragment創(chuàng)建默認工廠的代碼流程:

  1. androidxActivityFragment創(chuàng)建SavedStateViewModelFactory時杖虾,都傳入了Application,所以其工廠mFactoryAndroidViewModelFactory媒熊。
  2. create(String,Class<*>)方法奇适,如果ViewModel構(gòu)造方法里面沒有用SavedStateHandle坟比,則直接使用工廠mFactory(為AndroidViewModelFactory)進行創(chuàng)建。

說明:

  1. 使用SavedStateViewModelFactory創(chuàng)建嚷往,如果此ViewModel構(gòu)造方法里面沒有用SavedStateHandle葛账,則直接使用AndroidViewModelFactory創(chuàng)建;如果使用了皮仁,則反射創(chuàng)建(Application, SavedStateHandle)(SavedStateHandle)簽名的構(gòu)造方法籍琳。
  • 可以處理如下ViewModel
    • class MyViewModel : ViewModel()
    • class MyViewModel(application: Application) : AndroidViewModel(application)
    • class MyViewModel(val handle: SavedStateHandle) : ViewModel()
    • class MyViewModel(application: Application, val handle: SavedStateHandle) : AndroidViewModel(application)
  1. 由于SavedStateHandle的創(chuàng)建,傳入了當(dāng)前頁面傳入的參數(shù)贷祈,所以通過SavedStateHandle也能獲取到當(dāng)前頁面傳入的參數(shù)趋急。
  2. 使用SavedStateHandle相關(guān)的,將在Jetpact-保存狀態(tài)講解付燥。

說完了ViewModelProvider對象的創(chuàng)建宣谈,我們再來看看其get()方法是如果獲取ViewModel的愈犹。

ViewModelProvider.get方法

ViewModelProvider--> get方法

@MainThread
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
    // 獲取類名
    val canonicalName = modelClass.canonicalName
        ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
    // 使用默認名+類名作為key键科,獲取ViewModel。
    return get("$DEFAULT_KEY:$canonicalName", modelClass)
}

@Suppress("UNCHECKED_CAST")
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
    // 從ViewModelStore中獲取ViewModel
    var viewModel = store[key]
    if (modelClass.isInstance(viewModel)) {
        // viewModel不為空漩怎,并且是目標(biāo)類勋颖,直接返回。
        (factory as? OnRequeryFactory)?.onRequery(viewModel)
        return viewModel as T
    } else {
        @Suppress("ControlFlowWithEmptyBody")
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    // 沒有找到ViewModel勋锤,則直接創(chuàng)建饭玲,并存入到ViewModelStore中。
    viewModel = if (factory is KeyedFactory) {
        // 是KeyedFactory的子類直接調(diào)用create(key, modelClass)方法叁执。
        factory.create(key, modelClass)
    } else {
        factory.create(modelClass)
    }
    // 存入到ViewModelStore中
    store.put(key, viewModel)
    return viewModel
}

ViewModelProvider.get代碼流程:

  1. get(Class<*>)方法茄厘,使用默認名+類名作為key,調(diào)用get(String, Class<*>)方法谈宛,獲取ViewModel次哈。
  2. get(String, Class<*>)方法,先從ViewModelStore中獲取ViewModel吆录,如果有并且是目標(biāo)類窑滞,則直接返回,否則使用Factory直接創(chuàng)建恢筝,并存入到ViewModelStore中哀卫,以便后續(xù)獲取。

總結(jié)

以在androidxActivity內(nèi)獲取無參構(gòu)造方法ViewModel為例撬槽,講解代碼流程此改。

聲明ViewModel

class MyViewModel : ViewModel() {

    override fun onCleared() {
        super.onCleared()
    }
}

獲取ViewModel

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // 獲取ViewModel
        val model = ViewModelProvider(this).get(MyViewModel::class.java)      
    }
}

示例代碼流程:

  1. 創(chuàng)建ViewModelProvider,傳入的是ComponentActivity侄柔,它的ViewModelStoreComponentActivity提供的ViewModelStore共啃,它的FactoryComponentActivity提供的默認工廠SavedStateViewModelFactory鼓寺。
  2. get()方法,先從ViewModelStore中獲取ViewModel勋磕,如果有并且是目標(biāo)類妈候,則直接返回,否則使用FactorySavedStateViewModelFactory)直接創(chuàng)建挂滓,并存入到ViewModelStore中苦银,以便后續(xù)獲取。
  3. SavedStateViewModelFactorycreate()方法赶站,會直接調(diào)用AndroidViewModelFactorycreate()方法幔虏。(因為獲取的MyViewModel未使用SavedStateHandle,所以會直接調(diào)用mFactory的創(chuàng)建贝椿。又因為創(chuàng)建SavedStateViewModelFactory時傳入了Application想括,所以mFactoryAndroidViewModelFactory
  4. AndroidViewModelFactorycreate()方法,會直接使用反射創(chuàng)建無參構(gòu)造方法烙博。(因為獲取的MyViewModel未繼承AndroidViewModel瑟蜈,所以會走父類NewInstanceFactory的邏輯創(chuàng)建)

ViewModel生命周期

ViewModel生命周期為什么會比ActivityFragment的生命周期長渣窜,它是如何保持不變的铺根,以及它是如何被清除的,我們來分別分析以下乔宿。

ViewModel是如何保持不變的位迂?

ActivityFragment配置變更(如:屏幕旋轉(zhuǎn))的情況會銷毀重新創(chuàng)建,但是再次獲取的ViewModel實例不變详瑞。反向分析其原因掂林,要想要ViewModel實例不變,則需要保持ViewModelStore不變坝橡。我們分別看一下androidxActivityFragmentgetViewModelStore()方法泻帮。

Activity

ComponentActivity--> getViewModelStore方法

@NonNull
@Override
public ViewModelStore getViewModelStore() {
    if (getApplication() == null) {
        // 不能在onCreate調(diào)用之前獲取ViewModel
        throw new IllegalStateException("Your activity is not yet attached to the "
                + "Application instance. You can't request ViewModel before onCreate call.");
    }
    // 確保ViewModelStore
    ensureViewModelStore();
    // 返回ViewModelStore
    return mViewModelStore;
}

@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // 從 NonConfigurationInstances 中恢復(fù)ViewModelStore
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            // mViewModelStore為空,則創(chuàng)建驳庭。
            mViewModelStore = new ViewModelStore();
        }
    }
}

獲取ViewModelStore刑顺,我們先從NonConfigurationInstances中獲取,其內(nèi)部包含了一個ViewModelStore成員變量饲常,我們先來分析一下NonConfigurationInstances.viewModelStore是如何被賦值的蹲堂,然后再來分析又是如何獲取到它的。

說明:

  1. 為什么ComponentActivitymViewModelStore屬性贝淤,在配置變更之前存入值柒竞,而在配置變更之后為空?
  • 因為Activity配置變更之后播聪,重新創(chuàng)建的Activity朽基,Activity對象為新的布隔,所以其mViewModelStore屬性為初始狀態(tài):空。

ComponentActivity.NonConfigurationInstances類

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

通過查找引用稼虎,NonConfigurationInstances.viewModelStore是在ComponentActivityonRetainNonConfigurationInstance()方法里完成賦值的衅檀。

ComponentActivity--> onRetainNonConfigurationInstance方法

public final Object onRetainNonConfigurationInstance() {
    // Maintain backward compatibility.
    Object custom = onRetainCustomNonConfigurationInstance();

    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        // viewModelStore為空,則說明此時沒有調(diào)用過getViewModelStore()霎俩,則通過getLastNonConfigurationInstance()從重建之前的獲取哀军。
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            viewModelStore = nc.viewModelStore;
        }
    }

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

    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    // 記錄當(dāng)前viewModelStore,完成賦值操作打却。
    nci.viewModelStore = viewModelStore;
    return nci;
}

此方法杉适,創(chuàng)建ComponentActivity.NonConfigurationInstances對象,記錄當(dāng)前viewModelStore柳击,并返回此對象猿推。

說明:

  1. 重寫了父類ActivityonRetainNonConfigurationInstance() 方法,使其創(chuàng)建的ComponentActivity.NonConfigurationInstances對象捌肴,在配置變更之后不受影響蹬叭。
  2. ComponentActivity.NonConfigurationInstances.viewModelStore屬性,保存了在配置變更之前維護的ViewModelStore哭靖。

通過查找引用具垫,ComponentActivity.onRetainNonConfigurationInstance()方法是在ActivityretainNonConfigurationInstances()方法里調(diào)用的。

Activity--> retainNonConfigurationInstances方法

NonConfigurationInstances retainNonConfigurationInstances() {
    // 獲取到當(dāng)前activity要保存的數(shù)據(jù)
    Object activity = onRetainNonConfigurationInstance();
    HashMap<String, Object> children = onRetainNonConfigurationChildInstances();
    FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();

    // We're already stopped but we've been asked to retain.
    // Our fragments are taken care of but we need to mark the loaders for retention.
    // In order to do this correctly we need to restart the loaders first before
    // handing them off to the next activity.
    mFragments.doLoaderStart();
    mFragments.doLoaderStop(true);
    ArrayMap<String, LoaderManager> loaders = mFragments.retainLoaderNonConfig();

    if (activity == null && children == null && fragments == null && loaders == null
            && mVoiceInteractor == null) {
        return null;
        
    NonConfigurationInstances nci = new NonConfigurationInstances();
    // 記錄當(dāng)前activity數(shù)據(jù)试幽,完成賦值操作。
    nci.activity = activity;
    nci.children = children;
    nci.fragments = fragments;
    nci.loaders = loaders;
    if (mVoiceInteractor != null) {
        mVoiceInteractor.retainInstance();
        nci.voiceInteractor = mVoiceInteractor;
    }
    return nci;
}

此方法卦碾,創(chuàng)建Activity.NonConfigurationInstances對象铺坞,記錄其activity要保存數(shù)據(jù)(即ComponentActivity.NonConfigurationInstances對象),并返回此對象洲胖。

說明:

  1. ActivityretainNonConfigurationInstances() 方法济榨,使其創(chuàng)建的Activity.NonConfigurationInstances對象,在配置變更之后不受影響绿映。
  2. Activity.NonConfigurationInstances.activity屬性擒滑,保存了ComponentActivity.NonConfigurationInstances對象。

通過全局搜索叉弦,Activity.retainNonConfigurationInstances()方法是在ActivityThreadperformDestroyActivity()方法里調(diào)用的丐一。

ActivityThread--> performDestroyActivity方法

void performDestroyActivity(ActivityClientRecord r, boolean finishing,
        int configChanges, boolean getNonConfigInstance, String reason) {
    ...
    if (getNonConfigInstance) {
        try {
            // 從ActivityClientRecord的Activity中獲取Activity.NonConfigurationInstances對象,
            // 然后保存到它的lastNonConfigurationInstances中淹冰,完成保存操作库车。
            r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances();
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
                throw new RuntimeException("Unable to retain activity "
                        + r.intent.getComponent().toShortString() + ": " + e.toString(), e);
            }
        }
    }
    ...
        // 回調(diào)Activity的onDestroy方法
        mInstrumentation.callActivityOnDestroy(r.activity);
    ...
}

Activity執(zhí)行銷毀的時候,會先將不會因配置變更而改變的數(shù)據(jù)(即Activity.NonConfigurationInstances)保存到ActivityClientRecordlastNonConfigurationInstances屬性中樱拴。

說明:

  1. ActivityThread:它管理應(yīng)用程序進程中主線程的執(zhí)行柠衍、調(diào)度和執(zhí)行activity洋满、廣播以及activity manager請求的其它操作。
  2. ActivityClientRecordActivity客戶端記錄珍坊,用于真實的Activity實例的簿記牺勾。
  3. ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStore屬性,保存了在配置變更之前維護的ViewModelStore阵漏。

接下來禽最,我們來看一下是如果獲取到保存了在配置變更之前維護的ViewModelStore的,我們先來看一下Activity.getLastNonConfigurationInstance()方法袱饭。

Activity--> getLastNonConfigurationInstance方法

@Nullable
public Object getLastNonConfigurationInstance() {
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}

mLastNonConfigurationInstancesActivity.NonConfigurationInstances川无,getLastNonConfigurationInstance() 結(jié)果返回的是其activity屬性,即ComponentActivity.NonConfigurationInstances對象虑乖。

我們再來看一下懦趋,mLastNonConfigurationInstances是在哪里進行賦值的。通過查找疹味,mLastNonConfigurationInstances是在Activityattach()里賦值的仅叫。

Activity--> attach方法

@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
        IBinder shareableActivityToken) {
    ...
    // 完成賦值操作
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    ...
}

通過全局搜索,Activity.retainNonConfigurationInstances()方法是在ActivityThreadperformDestroyActivity()方法里調(diào)用的糙捺。

ActivityThread--> performLaunchActivity方法

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
            // 調(diào)用attach诫咱,傳入ActivityClientRecord的lastNonConfigurationInstances。
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback,
                    r.assistToken, r.shareableActivityToken);
    ...
    return activity;
}

Activity執(zhí)行啟動的時候洪灯,會調(diào)用其attach()方法坎缭,傳入ActivityClientRecord.lastNonConfigurationInstances保存的Activity.NonConfigurationInstances對象。

說明:

  1. 為什么ActivityThreadperformLaunchActivity()签钩、performDestroyActivity()方法里面ActivityClientRecord是同一個掏呼?
  • 因為ActivityClientRecord保存在了ActivityThread.mActivities屬性中,其為ActivityClientRecordMap集合铅檩,ActivityClientRecordstartActivityNow()方法內(nèi)創(chuàng)建憎夷,并調(diào)用performLaunchActivity()方法,在其內(nèi)部保存了創(chuàng)建的ActivityClientRecord對象昧旨,所以之后也能從Map中獲取到之前存入的ActivityClientRecord拾给,所以performLaunchActivity()performDestroyActivity()方法里面ActivityClientRecord是同一個兔沃。

代碼流程:

  1. ActivityThread.performDestroyActivity()方法蒋得,ActivityClientRecord.lastNonConfigurationInstances保存了Activity.retainNonConfigurationInstances()方法返回的Activity.NonConfigurationInstances對象。
  2. 其中的Activity.NonConfigurationInstances.activity屬性粘拾,保存了ComponentActivity.onRetainNonConfigurationInstance()方法返回的ComponentActivity.NonConfigurationInstances對象窄锅。
  3. 其中的ComponentActivity.NonConfigurationInstances.viewModelStore屬性,保存了在配置變更之前維護的ViewModelStore
  4. ActivityThread.performLaunchActivity()方法入偷,調(diào)用Activity.attach()方法追驴,傳入了保存在ActivityClientRecord.lastNonConfigurationInstancesActivity.NonConfigurationInstances對象。
  5. Activity.attach()方法疏之,保存了傳入的Activity.NonConfigurationInstances對象殿雪。
  6. 通過調(diào)用Activity.getLastNonConfigurationInstance()方法,即可拿到Activity.NonConfigurationInstances.activity屬性保存的ComponentActivity.NonConfigurationInstances對象锋爪。
  7. 最后獲取ComponentActivity.NonConfigurationInstances.viewModelStore屬性的值丙曙,即可拿到ComponentActivityViewModelStore對象。

總結(jié):

  1. Activity銷毀的時候其骄,ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStore屬性亏镰,保存了在配置變更之前維護的ViewModelStore
  2. Activity啟動的時候拯爽,ActivityClientRecord.lastNonConfigurationInstances的值在Activity.attach()的時候被存入到了Activity中索抓,所以后續(xù)也能獲取到在配置變更之前維護的ViewModelStore,所以配置變更前后獲取到的ViewModelStore毯炮、ViewModel實例不變逼肯。

Fragment

@NonNull
@Override
public ViewModelStore getViewModelStore() {
    if (mFragmentManager == null) {
    // 不能從detached的Fragment訪問ViewModels
        throw new IllegalStateException("Can't access ViewModels from detached fragment");
    }
    if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
        throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
                + "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
                + "supported");
    }
    return mFragmentManager.getViewModelStore(this);
}

mFragmentManagerFragmentManager,我們來看下其getViewModelStore()方法桃煎。

FragmentManager --> getViewModelStore方法

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}

mNonConfigFragmentManagerViewModel篮幢,我們先來看一下它是如果創(chuàng)建的,然后再來看一下其getViewModelStore()方法为迈。

通過查找三椿,發(fā)現(xiàn)其在FragmentManager.attachController()方法內(nèi)創(chuàng)建。

FragmentManager --> attachController方法

@SuppressWarnings("deprecation")
@SuppressLint("SyntheticAccessor")
void attachController(@NonNull FragmentHostCallback<?> host,
        @NonNull FragmentContainer container, @Nullable final Fragment parent) {
    ...
    // Get the FragmentManagerViewModel
    if (parent != null) {
        // 當(dāng)parent不為null時曲尸,調(diào)用父FragmentManager的getChildNonConfig獲取赋续。
        mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
    } else if (host instanceof ViewModelStoreOwner) {
        // 從host中獲取ViewModelStore,然后使用FragmentManagerViewModel進行獲取另患。
        ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
        mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
    } else {
        mNonConfig = new FragmentManagerViewModel(false);
    }
    ...
}

通過查找,發(fā)現(xiàn)attachController方法會在Fragmentattach的時候調(diào)用蛾绎,其中hostFragmentActivity的內(nèi)部類FragmentActivity.HostCallbacks昆箕,它實現(xiàn)了ViewModelStoreOwner接口。

創(chuàng)建mNonConfig租冠,如果沒有父Fragment鹏倘,則會從host中調(diào)用getViewModelStore()方法獲取ViewModelStore,然后調(diào)用FragmentManagerViewModel.getInstance(viewModelStore)進行獲取FragmentManagerViewModel顽爹。

因為一般沒有父Fragment纤泵,大部分走第二個if,所以我們先來分析它镜粤,我們先來看一下FragmentActivity.HostCallbacksgetViewModelStore()方法捏题,然后再來看一下FragmentManagerViewModelgetInstance()方法玻褪。

FragmentActivity.HostCallbacks --> getViewModelStore方法

class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
        ViewModelStoreOwner,
        OnBackPressedDispatcherOwner,
        ActivityResultRegistryOwner,
        SavedStateRegistryOwner,
        FragmentOnAttachListener {
    ...
    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        return FragmentActivity.this.getViewModelStore();
    }
    ...
}

FragmentActivity.HostCallbacksgetViewModelStore()方法,直接調(diào)用了FragmentActivitygetViewModelStore()方法公荧,即調(diào)用了其父類ComponentActivitygetViewModelStore()方法带射。

所以FragmentManager.attachController()方法內(nèi),通過host也能獲取到ComponentActivityViewModelStore循狰。

接下來窟社,我們再來看一下FragmentManagerViewModelgetInstance()方法。

FragmentManagerViewModel --> getInstance方法

final class FragmentManagerViewModel extends ViewModel {
    private static final String TAG = FragmentManager.TAG;

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

FragmentManagerViewModel是一個ViewModel绪钥,getInstance(ViewModelStore)方法會先從傳入的ViewModelStore(即ComponentActivityViewModelStore)中獲取灿里,如果沒有則使用FACTORY進行創(chuàng)建FragmentManagerViewModel

說明:

  1. 傳入的ViewModelStoreComponentActivityViewModelStore程腹,一開始ViewModelStore內(nèi)是沒有FragmentManagerViewModel的匣吊,所以創(chuàng)建FragmentManagerViewModel并存入其ComponentActivityViewModelStore中篇亭。
  2. 由于ComponentActivityViewModelStore配置變更后實例不變创葡,所以FragmentManagerViewModel.getInstance()方法也能從ComponentActivityViewModelStore中獲取到配置變更前存入的FragmentManagerViewModel實例娘荡。

說完了FragmentManagerViewModel的創(chuàng)建裸诽,我們再來看一下其getViewModelStore()方法萧芙。

FragmentManagerViewModel --> getViewModelStore方法

@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}

getViewModelStore(Fragment)方法牛曹,獲取到指定FragmentViewModelStore切心,如果沒有則進行創(chuàng)建保存mViewModelStores中灼捂,mViewModelStoresViewModelStoreMap集合池户。

說明:

  1. 為什么FragmentManagerViewModel.getViewModelStore(Fragment)方法咏雌,要傳入Fragment才能獲取到ViewModelStore
  • 因為FragmentManagerViewModel校焦,保存到了ComponentActivityViewModelStore中赊抖,所以每個Fragment獲取到的FragmentManagerViewModel實例相同,所以需要傳入Fragment實例區(qū)分是獲取ViewModelStore集合的哪個寨典。
  1. 為什么Fragment配置變更前后獲取到的ViewModelStore氛雪、ViewModel實例不變
  • 因為ComponentActivity配置變更前后獲取到的ViewModelStore耸成、ViewModel實例不變报亩,所以存在ComponentActivityViewModelStore中的FragmentManagerViewModel實例不變,所以存在mViewModelStores的各個FragmentViewModelStore實例不變井氢,所以ViewModel實例不變弦追。

代碼流程:

  1. Fragmentattach的時候,獲取到了ComponentActivityViewModelStore花竞,創(chuàng)建FragmentManagerViewModel并存入到ComponentActivityViewModelStore中劲件。
  2. FragmentManagerViewModel.getViewModelStore(Fragment)方法,通過FragmentmViewModelStores中獲取到對應(yīng)的ViewModelStore,如果沒有則進行創(chuàng)建后保存到mViewModelStores中零远。

ViewModel是如何被清除的苗分?

要想分析ViewModel是如何被清除的,則需要分析ViewModelStore是如何被清除的遍烦。

Activity

通過引用查找俭嘁,我們發(fā)現(xiàn)在ComponentActivity的構(gòu)造方法里面調(diào)用了ViewModelStore的清除操作。

ComponentActivity類

public ComponentActivity() {
    Lifecycle lifecycle = getLifecycle();
    //noinspection ConstantConditions
    if (lifecycle == null) {
        throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
                + "constructor. Please make sure you are lazily constructing your Lifecycle "
                + "in the first call to getLifecycle() rather than relying on field "
                + "initialization.");
    }
    ...
    getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (event == Lifecycle.Event.ON_DESTROY) {
                // Clear out the available context
                mContextAwareHelper.clearAvailableContext();
                // And clear the ViewModelStore
                if (!isChangingConfigurations()) {
                    // 不是配置變更服猪,清除全部ViewModel供填。
                    getViewModelStore().clear();
                }
            }
        }
    });
    ...
}

使用Lifecycle觀察當(dāng)前生命周期的狀態(tài),如果事件處于ON_DESTROY并且不是配置變更罢猪,則清空全部ViewModel近她。

說明:

  1. ActivityViewModel是如何被清除的?
  • 使用Lifecycle觀察當(dāng)前生命周期的狀態(tài)膳帕,如果事件處于ON_DESTROY并且不是配置變更粘捎,則清空全部ViewModel

Fragment

通過引用查找危彩,我們發(fā)現(xiàn)在FragmentManagerViewModelclearNonConfigStateInternal方法里面調(diào)用了ViewModelStore的清除操作攒磨。

FragmentManagerViewModel --> clearNonConfigStateInternal方法

void clearNonConfigState(@NonNull Fragment f) {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "Clearing non-config state for " + f);
    }
    clearNonConfigStateInternal(f.mWho);
}

void clearNonConfigState(@NonNull String who) {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "Clearing non-config state for saved state of Fragment " + who);
    }
    clearNonConfigStateInternal(who);
}

private void clearNonConfigStateInternal(@NonNull String who) {
    // Clear and remove the Fragment's child non config state
    FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(who);
    if (childNonConfig != null) {
        childNonConfig.onCleared();
        mChildNonConfigs.remove(who);
    }
    // Clear and remove the Fragment's ViewModelStore
    // 獲取到對應(yīng)Fragment的ViewModelStore
    ViewModelStore viewModelStore = mViewModelStores.get(who);
    if (viewModelStore != null) {
    // 清除全部ViewModel。
        viewModelStore.clear();
        mViewModelStores.remove(who);
    }
}

clearNonConfigStateInternal(String)方法汤徽,會獲取到對應(yīng)FragmentViewModelStore娩缰,然后調(diào)用其clear()方法清除全部ViewModel

通過引用查找谒府,我們發(fā)現(xiàn)在clearNonConfigStateInternal(String)方法被clearNonConfigState(Fragment)拼坎、clearNonConfigState(String)方法調(diào)用,然后它兩又被幾處調(diào)用完疫,最后通過Debug發(fā)現(xiàn)FragmentStateManager.destroy()方法泰鸡,執(zhí)行了clearNonConfigState(Fragment)方法。

FragmentStateManager --> destroy方法

void destroy() {
    ...
    if (shouldDestroy) {
        FragmentHostCallback<?> host = mFragment.mHost;
        boolean shouldClear;
        if (host instanceof ViewModelStoreOwner) {
            shouldClear = mFragmentStore.getNonConfig().isCleared();
        } else if (host.getContext() instanceof Activity) {
            Activity activity = (Activity) host.getContext();
            shouldClear = !activity.isChangingConfigurations();
        } else {
            shouldClear = true;
        }
        if ((beingRemoved && !mFragment.mBeingSaved) || shouldClear) {
        // 執(zhí)行FragmentManagerViewModel的clearNonConfigState(Fragment)壳鹤,清除不會因配置變更而改變的狀態(tài)盛龄。
            mFragmentStore.getNonConfig().clearNonConfigState(mFragment);
        }
        ...
    }
    ...
}

hostFragmentActivity.HostCallbacks,它實現(xiàn)了ViewModelStoreOwner接口芳誓,所以會走第一個if讯嫂。只要shouldCleartrue的時候,就會執(zhí)行到FragmentManagerViewModelclearNonConfigState(Fragment)方法兆沙,我們來看一下FragmentManagerViewModelisCleared()方法的返回值是什么?

FragmentManagerViewModel --> isCleared方法

final class FragmentManagerViewModel extends ViewModel {

    @Override
    protected void onCleared() {
        if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
            Log.d(TAG, "onCleared called for " + this);
        }
        // 標(biāo)記已經(jīng)被清理
        mHasBeenCleared = true;
    }

    boolean isCleared() {
        return mHasBeenCleared;
    }
}

FragmentManagerViewModel是一個ViewModel莉掂,被添加到了ComponentActivityViewModelStore中葛圃,當(dāng)ComponentActivityViewModelStore被清除的時候(事件為ON_DESTROY并且不是配置變更),會調(diào)用ViewModelonCleared()方法,則mHasBeenClearedtrue库正,即isCleared()方法返回為true曲楚。

因為isCleared()方法返回為true,所以FragmentStateManager.destroy()方法內(nèi)會執(zhí)行到FragmentManagerViewModelclearNonConfigState(Fragment)方法褥符,會獲取到對應(yīng)FragmentViewModelStore龙誊,然后調(diào)用其clear()方法清除全部ViewModel

說明:

  1. FragmentViewModel是如何被清除的喷楣?
  • FragmentManagerViewModel是一個ViewModel趟大,被添加到了ComponentActivityViewModelStore中,當(dāng)ComponentActivityViewModelStore被清除的時候(事件為ON_DESTROY并且不是配置變更)铣焊,會調(diào)用ViewModelonCleared()方法逊朽,則mHasBeenClearedtrue,即isCleared()方法返回為true曲伊,所以FragmentStateManager.destroy()方法內(nèi)會執(zhí)行到FragmentManagerViewModelclearNonConfigState(Fragment)方法叽讳,會獲取到對應(yīng)FragmentViewModelStore,然后調(diào)用其clear()方法清除全部ViewModel坟募。

總結(jié)

以上就是全面的Jetpack-ViewModel源碼了岛蚤!之后會出Jetpack其它源碼系列,請及時關(guān)注懈糯。如果你有什么問題涤妒,大家評論區(qū)見!

最后推薦一下我的網(wǎng)站昂利,開發(fā)者的技術(shù)博客: devbolg.cn 届腐,目前包含android相關(guān)的技術(shù),之后會面向全部開發(fā)者蜂奸,歡迎大家來體驗犁苏!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扩所,隨后出現(xiàn)的幾起案子围详,更是在濱河造成了極大的恐慌,老刑警劉巖祖屏,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件助赞,死亡現(xiàn)場離奇詭異,居然都是意外死亡袁勺,警方通過查閱死者的電腦和手機雹食,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來期丰,“玉大人群叶,你說我怎么就攤上這事吃挑。” “怎么了街立?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵舶衬,是天一觀的道長。 經(jīng)常有香客問我赎离,道長逛犹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任梁剔,我火速辦了婚禮虽画,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘憾朴。我一直安慰自己狸捕,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布众雷。 她就那樣靜靜地躺著灸拍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砾省。 梳的紋絲不亂的頭發(fā)上鸡岗,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天,我揣著相機與錄音编兄,去河邊找鬼轩性。 笑死,一個胖子當(dāng)著我的面吹牛狠鸳,可吹牛的內(nèi)容都是我干的揣苏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼件舵,長吁一口氣:“原來是場噩夢啊……” “哼卸察!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起铅祸,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤坑质,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后临梗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體涡扼,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年盟庞,在試婚紗的時候發(fā)現(xiàn)自己被綠了吃沪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡什猖,死狀恐怖巷波,靈堂內(nèi)的尸體忽然破棺而出萎津,到底是詐尸還是另有隱情,我是刑警寧澤抹镊,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站荤傲,受9級特大地震影響垮耳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜遂黍,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一终佛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雾家,春花似錦铃彰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至敬飒,卻和暖如春邪铲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背无拗。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工带到, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人英染。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓揽惹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親四康。 傳聞我的和親對象是個殘疾皇子搪搏,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容