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生命周期
源碼
聲明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
)
}
ViewModelProvider
為ViewModel
提供者,創(chuàng)建它需要ViewModelStore
和ViewModelProvider.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();
}
}
ViewModelProvider
為ViewModel
商店,它是用來存儲或獲取ViewModel
的躏救,是使用HashMap
來實現(xiàn)的唯笙。其clear
方法會清除內(nèi)部存儲并通知ViewModels
它們不再使用。
ViewModelStoreOwner
ViewModelStoreOwner類
public interface ViewModelStoreOwner {
@NonNull
ViewModelStore getViewModelStore();
}
ViewModelStoreOwner
為ViewModelStore
的持有者落剪,通過它的子類可以獲取到ViewModelStore
睁本。androidx
的Activity
和Fragment
都已經(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)建。
說明:
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)建。
說明:
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.Factory
為ViewModel
的創(chuàng)建工廠畏吓,此Factory
通過ViewModel
類的class
,創(chuàng)建ViewModel
實例卫漫。我們分別來看一下它的子類KeyedFactory
菲饼、NewInstanceFactory
、AndroidViewModelFactory
汛兜。
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"
)
}
}
KeyedFactory
為Factory
的抽象子類巴粪,重寫了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!!
}
}
}
NewInstanceFactory
為Factory
的子類,實現(xiàn)了create(Class<?>)
方法辫塌,通過ViewModel
類的class
漏策,無參反射創(chuàng)建ViewModel
實例。
說明:
- 使用
NewInstanceFactory
創(chuàng)建臼氨,此ViewModel
必須有無參的且不是私有的構(gòu)造方法掺喻。
- 可以處理如下
ViewModel
:
class MyViewModel : ViewModel()
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!!
}
}
}
AndroidViewModelFactory
為NewInstanceFactory
的子類呀狼,重寫了create(Class<?>)
方法裂允,通過ViewModel
類的class
判斷,如果此ViewModel
為AndroidViewModel
的子類哥艇,則傳入Application
并反射創(chuàng)建绝编,否則走父類邏輯無參反射創(chuàng)建ViewModel
實例。
說明:
- 使用
AndroidViewModelFactory
創(chuàng)建貌踏,如果此ViewModel
是AndroidViewModel
子類十饥,必須有一參的且是Application
且不是私有的構(gòu)造方法(不能無參);否則必須有無參的且不是私有的構(gòu)造方法(不能有參)哩俭。
- 可以處理如下
ViewModel
:
class MyViewModel : ViewModel()
class MyViewModel(application: Application) : AndroidViewModel(application)
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
梆暖。androidx
的Activity
和Fragment
都已經(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;
}
}
androidx
的Activity
和Fragment
的實現(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);
}
}
androidx
的Activity
和Fragment
創(chuàng)建默認工廠的代碼流程:
androidx
的Activity
和Fragment
創(chuàng)建SavedStateViewModelFactory
時杖虾,都傳入了Application
,所以其工廠mFactory
為AndroidViewModelFactory
媒熊。create(String,Class<*>)
方法奇适,如果ViewModel
構(gòu)造方法里面沒有用SavedStateHandle
坟比,則直接使用工廠mFactory
(為AndroidViewModelFactory
)進行創(chuàng)建。
說明:
- 使用
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)
- 由于
SavedStateHandle
的創(chuàng)建,傳入了當(dāng)前頁面傳入的參數(shù)贷祈,所以通過SavedStateHandle
也能獲取到當(dāng)前頁面傳入的參數(shù)趋急。- 使用
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
代碼流程:
get(Class<*>)
方法茄厘,使用默認名+類名作為key
,調(diào)用get(String, Class<*>)
方法谈宛,獲取ViewModel
次哈。get(String, Class<*>)
方法,先從ViewModelStore
中獲取ViewModel
吆录,如果有并且是目標(biāo)類窑滞,則直接返回,否則使用Factory
直接創(chuàng)建恢筝,并存入到ViewModelStore
中哀卫,以便后續(xù)獲取。
總結(jié)
以在androidx
的Activity
內(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)
}
}
示例代碼流程:
- 創(chuàng)建
ViewModelProvider
,傳入的是ComponentActivity
侄柔,它的ViewModelStore
為ComponentActivity
提供的ViewModelStore
共啃,它的Factory
為ComponentActivity
提供的默認工廠SavedStateViewModelFactory
鼓寺。get()
方法,先從ViewModelStore
中獲取ViewModel
勋磕,如果有并且是目標(biāo)類妈候,則直接返回,否則使用Factory
(SavedStateViewModelFactory
)直接創(chuàng)建挂滓,并存入到ViewModelStore
中苦银,以便后續(xù)獲取。SavedStateViewModelFactory
的create()
方法赶站,會直接調(diào)用AndroidViewModelFactory
的create()
方法幔虏。(因為獲取的MyViewModel
未使用SavedStateHandle
,所以會直接調(diào)用mFactory
的創(chuàng)建贝椿。又因為創(chuàng)建SavedStateViewModelFactory
時傳入了Application
想括,所以mFactory
為AndroidViewModelFactory
)AndroidViewModelFactory
的create()
方法,會直接使用反射創(chuàng)建無參構(gòu)造方法烙博。(因為獲取的MyViewModel
未繼承AndroidViewModel
瑟蜈,所以會走父類NewInstanceFactory
的邏輯創(chuàng)建)
ViewModel生命周期
ViewModel
生命周期為什么會比Activity
、Fragment
的生命周期長渣窜,它是如何保持不變的铺根,以及它是如何被清除的,我們來分別分析以下乔宿。
ViewModel是如何保持不變的位迂?
Activity
和Fragment
在配置變更(如:屏幕旋轉(zhuǎn))的情況會銷毀并重新創(chuàng)建,但是再次獲取的ViewModel
實例不變详瑞。反向分析其原因掂林,要想要ViewModel
實例不變,則需要保持ViewModelStore
不變坝橡。我們分別看一下androidx
的Activity
和Fragment
的getViewModelStore()
方法泻帮。
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
是如何被賦值的蹲堂,然后再來分析又是如何獲取到它的。
說明:
- 為什么
ComponentActivity
的mViewModelStore
屬性贝淤,在配置變更之前存入值柒竞,而在配置變更之后為空?
- 因為
Activity
在配置變更之后播聪,重新創(chuàng)建的Activity
朽基,Activity
對象為新的布隔,所以其mViewModelStore
屬性為初始狀態(tài):空。
ComponentActivity.NonConfigurationInstances類
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
通過查找引用稼虎,NonConfigurationInstances.viewModelStore
是在ComponentActivity
的onRetainNonConfigurationInstance()
方法里完成賦值的衅檀。
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
柳击,并返回此對象猿推。
說明:
- 重寫了父類
Activity
的onRetainNonConfigurationInstance()
方法,使其創(chuàng)建的ComponentActivity.NonConfigurationInstances
對象捌肴,在配置變更之后不受影響蹬叭。ComponentActivity.NonConfigurationInstances.viewModelStore
屬性,保存了在配置變更之前維護的ViewModelStore
哭靖。
通過查找引用具垫,ComponentActivity.onRetainNonConfigurationInstance()
方法是在Activity
的retainNonConfigurationInstances()
方法里調(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
對象),并返回此對象洲胖。
說明:
Activity
的retainNonConfigurationInstances()
方法济榨,使其創(chuàng)建的Activity.NonConfigurationInstances
對象,在配置變更之后不受影響绿映。Activity.NonConfigurationInstances.activity
屬性擒滑,保存了ComponentActivity.NonConfigurationInstances
對象。
通過全局搜索叉弦,Activity.retainNonConfigurationInstances()
方法是在ActivityThread
的performDestroyActivity()
方法里調(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
)保存到ActivityClientRecord
的lastNonConfigurationInstances
屬性中樱拴。
說明:
ActivityThread
:它管理應(yīng)用程序進程中主線程的執(zhí)行柠衍、調(diào)度和執(zhí)行activity
洋满、廣播以及activity manager
請求的其它操作。ActivityClientRecord
:Activity
客戶端記錄珍坊,用于真實的Activity
實例的簿記牺勾。ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStore
屬性,保存了在配置變更之前維護的ViewModelStore
阵漏。
接下來禽最,我們來看一下是如果獲取到保存了在配置變更之前維護的ViewModelStore
的,我們先來看一下Activity.getLastNonConfigurationInstance()
方法袱饭。
Activity--> getLastNonConfigurationInstance方法
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null
? mLastNonConfigurationInstances.activity : null;
}
mLastNonConfigurationInstances
為Activity.NonConfigurationInstances
川无,getLastNonConfigurationInstance()
結(jié)果返回的是其activity
屬性,即ComponentActivity.NonConfigurationInstances
對象虑乖。
我們再來看一下懦趋,mLastNonConfigurationInstances
是在哪里進行賦值的。通過查找疹味,mLastNonConfigurationInstances
是在Activity
的attach()
里賦值的仅叫。
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()
方法是在ActivityThread
的performDestroyActivity()
方法里調(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
對象。
說明:
- 為什么
ActivityThread
的performLaunchActivity()
签钩、performDestroyActivity()
方法里面ActivityClientRecord
是同一個掏呼?
- 因為
ActivityClientRecord
保存在了ActivityThread.mActivities
屬性中,其為ActivityClientRecord
的Map
集合铅檩,ActivityClientRecord
在startActivityNow()
方法內(nèi)創(chuàng)建憎夷,并調(diào)用performLaunchActivity()
方法,在其內(nèi)部保存了創(chuàng)建的ActivityClientRecord
對象昧旨,所以之后也能從Map
中獲取到之前存入的ActivityClientRecord
拾给,所以performLaunchActivity()
、performDestroyActivity()
方法里面ActivityClientRecord
是同一個兔沃。
代碼流程:
- 在
ActivityThread.performDestroyActivity()
方法蒋得,ActivityClientRecord.lastNonConfigurationInstances
保存了Activity.retainNonConfigurationInstances()
方法返回的Activity.NonConfigurationInstances
對象。- 其中的
Activity.NonConfigurationInstances.activity
屬性粘拾,保存了ComponentActivity.onRetainNonConfigurationInstance()
方法返回的ComponentActivity.NonConfigurationInstances
對象窄锅。- 其中的
ComponentActivity.NonConfigurationInstances.viewModelStore
屬性,保存了在配置變更之前維護的ViewModelStore
。- 在
ActivityThread.performLaunchActivity()
方法入偷,調(diào)用Activity.attach()
方法追驴,傳入了保存在ActivityClientRecord.lastNonConfigurationInstances
的Activity.NonConfigurationInstances
對象。Activity.attach()
方法疏之,保存了傳入的Activity.NonConfigurationInstances
對象殿雪。- 通過調(diào)用
Activity.getLastNonConfigurationInstance()
方法,即可拿到Activity.NonConfigurationInstances.activity
屬性保存的ComponentActivity.NonConfigurationInstances
對象锋爪。- 最后獲取
ComponentActivity.NonConfigurationInstances.viewModelStore
屬性的值丙曙,即可拿到ComponentActivity
的ViewModelStore
對象。
總結(jié):
- 在
Activity
銷毀的時候其骄,ActivityClientRecord.lastNonConfigurationInstances.activity.viewModelStore
屬性亏镰,保存了在配置變更之前維護的ViewModelStore
。- 在
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);
}
mFragmentManager
為FragmentManager
,我們來看下其getViewModelStore()
方法桃煎。
FragmentManager --> getViewModelStore方法
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
return mNonConfig.getViewModelStore(f);
}
mNonConfig
為FragmentManagerViewModel
篮幢,我們先來看一下它是如果創(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
方法會在Fragment
的attach
的時候調(diào)用蛾绎,其中host
為FragmentActivity
的內(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.HostCallbacks
的getViewModelStore()
方法捏题,然后再來看一下FragmentManagerViewModel
的getInstance()
方法玻褪。
FragmentActivity.HostCallbacks --> getViewModelStore方法
class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
ViewModelStoreOwner,
OnBackPressedDispatcherOwner,
ActivityResultRegistryOwner,
SavedStateRegistryOwner,
FragmentOnAttachListener {
...
@NonNull
@Override
public ViewModelStore getViewModelStore() {
return FragmentActivity.this.getViewModelStore();
}
...
}
FragmentActivity.HostCallbacks
的getViewModelStore()
方法,直接調(diào)用了FragmentActivity
的getViewModelStore()
方法公荧,即調(diào)用了其父類ComponentActivity
的getViewModelStore()
方法带射。
所以FragmentManager.attachController()
方法內(nèi),通過host
也能獲取到ComponentActivity
的ViewModelStore
循狰。
接下來窟社,我們再來看一下FragmentManagerViewModel
的getInstance()
方法。
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
(即ComponentActivity
的ViewModelStore
)中獲取灿里,如果沒有則使用FACTORY
進行創(chuàng)建FragmentManagerViewModel
。
說明:
- 傳入的
ViewModelStore
為ComponentActivity
的ViewModelStore
程腹,一開始ViewModelStore
內(nèi)是沒有FragmentManagerViewModel
的匣吊,所以創(chuàng)建FragmentManagerViewModel
并存入其ComponentActivity
的ViewModelStore
中篇亭。- 由于
ComponentActivity
的ViewModelStore
配置變更后實例不變创葡,所以FragmentManagerViewModel.getInstance()
方法也能從ComponentActivity
的ViewModelStore
中獲取到配置變更前存入的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)
方法牛曹,獲取到指定Fragment
的ViewModelStore
切心,如果沒有則進行創(chuàng)建并保存到mViewModelStores
中灼捂,mViewModelStores
為ViewModelStore
的Map
集合池户。
說明:
- 為什么
FragmentManagerViewModel.getViewModelStore(Fragment)
方法咏雌,要傳入Fragment
才能獲取到ViewModelStore
?
- 因為
FragmentManagerViewModel
校焦,保存到了ComponentActivity
的ViewModelStore
中赊抖,所以每個Fragment
獲取到的FragmentManagerViewModel
實例相同,所以需要傳入Fragment
實例區(qū)分是獲取ViewModelStore
集合的哪個寨典。
- 為什么
Fragment
在配置變更前后獲取到的ViewModelStore
氛雪、ViewModel
實例不變?
- 因為
ComponentActivity
在配置變更前后獲取到的ViewModelStore
耸成、ViewModel
實例不變报亩,所以存在ComponentActivity
的ViewModelStore
中的FragmentManagerViewModel
實例不變,所以存在mViewModelStores
的各個Fragment
的ViewModelStore
實例不變井氢,所以ViewModel
實例不變弦追。
代碼流程:
Fragment
的attach
的時候,獲取到了ComponentActivity
的ViewModelStore
花竞,創(chuàng)建FragmentManagerViewModel
并存入到ComponentActivity
的ViewModelStore
中劲件。FragmentManagerViewModel.getViewModelStore(Fragment)
方法,通過Fragment
從mViewModelStores
中獲取到對應(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
近她。
說明:
Activity
的ViewModel
是如何被清除的?
- 使用
Lifecycle
觀察當(dāng)前生命周期的狀態(tài)膳帕,如果事件處于ON_DESTROY
并且不是配置變更粘捎,則清空全部ViewModel
。
Fragment
通過引用查找危彩,我們發(fā)現(xiàn)在FragmentManagerViewModel
的clearNonConfigStateInternal
方法里面調(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)Fragment
的ViewModelStore
娩缰,然后調(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);
}
...
}
...
}
host
為FragmentActivity.HostCallbacks
,它實現(xiàn)了ViewModelStoreOwner
接口芳誓,所以會走第一個if
讯嫂。只要shouldClear
為true
的時候,就會執(zhí)行到FragmentManagerViewModel
的clearNonConfigState(Fragment)
方法兆沙,我們來看一下FragmentManagerViewModel
的isCleared()
方法的返回值是什么?
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
莉掂,被添加到了ComponentActivity
的ViewModelStore
中葛圃,當(dāng)ComponentActivity
的ViewModelStore
被清除的時候(事件為ON_DESTROY
并且不是配置變更),會調(diào)用ViewModel
的onCleared()
方法,則mHasBeenCleared
為true
库正,即isCleared()
方法返回為true
曲楚。
因為isCleared()
方法返回為true
,所以FragmentStateManager.destroy()
方法內(nèi)會執(zhí)行到FragmentManagerViewModel
的clearNonConfigState(Fragment)
方法褥符,會獲取到對應(yīng)Fragment
的ViewModelStore
龙誊,然后調(diào)用其clear()
方法清除全部ViewModel
。
說明:
Fragment
的ViewModel
是如何被清除的喷楣?
FragmentManagerViewModel
是一個ViewModel
趟大,被添加到了ComponentActivity
的ViewModelStore
中,當(dāng)ComponentActivity
的ViewModelStore
被清除的時候(事件為ON_DESTROY
并且不是配置變更)铣焊,會調(diào)用ViewModel
的onCleared()
方法逊朽,則mHasBeenCleared
為true
,即isCleared()
方法返回為true
曲伊,所以FragmentStateManager.destroy()
方法內(nèi)會執(zhí)行到FragmentManagerViewModel
的clearNonConfigState(Fragment)
方法叽讳,會獲取到對應(yīng)Fragment
的ViewModelStore
,然后調(diào)用其clear()
方法清除全部ViewModel
坟募。
總結(jié)
以上就是全面的Jetpack-ViewModel
源碼了岛蚤!之后會出Jetpack
其它源碼系列,請及時關(guān)注懈糯。如果你有什么問題涤妒,大家評論區(qū)見!
最后推薦一下我的網(wǎng)站昂利,開發(fā)者的技術(shù)博客: devbolg.cn 届腐,目前包含android相關(guān)的技術(shù),之后會面向全部開發(fā)者蜂奸,歡迎大家來體驗犁苏!