一、介紹
ViewModel就是存儲頁面相關(guān)的數(shù)據(jù),并將這些數(shù)據(jù)和Activity、Fragment等有生命周期相關(guān)的組件相關(guān)聯(lián),賦予數(shù)據(jù)生命周期。
特點(diǎn):
將數(shù)據(jù)與界面控制器進(jìn)行分離(也就是將經(jīng)常在Actvity、Fragment中的保存的數(shù)據(jù)分離出來,這樣這樣界面控制器就主要負(fù)責(zé)與UI相關(guān)的事情即可)
加大保存數(shù)據(jù)的范圍(當(dāng)頁面發(fā)送無意關(guān)閉時(shí),我們一般是onSaveInstanceState()來保存數(shù)據(jù),但是這樣保存的數(shù)據(jù)大小有限制,而且是必須可序列化再反序列化的數(shù)據(jù),而viewmodel可以保存我們頁面所需的所有數(shù)據(jù))
分離界面控制器的工作(將一些與數(shù)據(jù)相關(guān)的業(yè)務(wù)處理分來出來,減少控制器對業(yè)務(wù)的處理工作)
ViewModel 保存的數(shù)據(jù)會在activity完成時(shí),由框架調(diào)用onCleared方法清理資源
ViewModel的生命周期
在viewModel對象創(chuàng)建時(shí)開始,一直到他所關(guān)聯(lián)的界面控制器銷毀時(shí)才銷毀,這就說明了即使發(fā)生了橫豎屏切換,界面相關(guān)的數(shù)據(jù)也是一直存在并且不受橫豎屏切換的影響。
通常我們是在Actvity的onCreate()方法中來創(chuàng)建ViewModel對象,該ViewModel對象會一直在內(nèi)存中,直到這個(gè)Activity銷毀時(shí)才釋放資源。
二、使用
1、 添加依賴
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0-alpha03"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-alpha03"
2、 創(chuàng)建viewmodel
class MainViewModel:ViewModel() {
var name:String="Leon"
var position:MutableLiveData<String> = MutableLiveData()
}
3、 簡單使用
class MainActivity : AppCompatActivity() {
val TAG=MainActivity::class.java.simpleName
lateinit var viewModel:MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel= ViewModelProvider(this).get(MainViewModel::class.java)
//下面是結(jié)合LiveData來使用ViewModel的數(shù)據(jù)的
viewModel.position.observe(this,{
Log.e(TAG, "onCreate: position value = ${it}")
})
}
}
三、工作原理
原理:
當(dāng)開始創(chuàng)建Activity的實(shí)例對象時(shí),會生成用來存儲ViewModel對象的ViewModelStore實(shí)例(使用Hashmap數(shù)據(jù)結(jié)構(gòu)存儲),并給當(dāng)前Activity的生命周期添加觀察者,用于觀察Activity的生命周期變化,當(dāng)Activity的生命周期是ON_DESTROY時(shí),就會清理掉ViewModelStore中存儲的ViewModel的所有對象,釋放資源。
創(chuàng)建ViewModelProvider對象實(shí)例時(shí),會在其構(gòu)造中調(diào)用生成一個(gè)AndroidViewModelFactory的全局工程對象,我們會使用這個(gè)工廠對象來反射自定義的ViewModel對象。
當(dāng)使用ViewModelProvider對象實(shí)例get自定義的ViewModel對象時(shí),會先從ViewModelStore的Hashmap去找,如果沒有找到,就用上一步的AndroidViewModelFactory實(shí)例來反射自定義的ViewModel對象,并將該ViewModel保存到Hashmap中,下次使用的時(shí)候就可以直接使用;如果找了ViewModel 就直接返回該ViewModel的對象。
從上面ViewModel的工作原理可以得知:
1、ViewModel 一旦創(chuàng)建好了,就會一直保存到當(dāng)前界面控制器(Activity 、Fragment等)銷毀時(shí)才會釋放資源;
2、不同的界面控制器,ViewModel 的對象時(shí)存在不同的Hashmap中的,他們也是不同的對象;局部單例;
3、要做到全局單例ViewModel對象,可以將ViewModel放到Application中去;
接下來從源碼角度來分析一下原理:
1、創(chuàng)建存儲ViewModel的容器ViewModelStore對象
在構(gòu)建Activity的對象時(shí),在其父類ComponentActivity.java中實(shí)現(xiàn)了接口ViewModelStoreOwner,在其實(shí)現(xiàn)方法中生成ViewModelStore對象
//ComponentActivity.java
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;
}
2、ViewModelProvider(this)生成AndroidViewModelFactory工廠對象
//ViewModelProvider.kt
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner))
//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 {
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)
}
public companion object {
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
if (owner is HasDefaultViewModelProviderFactory)
owner.defaultViewModelProviderFactory else instance
internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"
private var sInstance: AndroidViewModelFactory? = null
/**
* Retrieve a singleton instance of AndroidViewModelFactory.
*
* @param application an application to pass in [AndroidViewModel]
* @return A valid [AndroidViewModelFactory]
*/
@JvmStatic
public fun getInstance(application: Application): AndroidViewModelFactory {
if (sInstance == null) {
//**** 生成全局的ViewModelFactory對象
sInstance = AndroidViewModelFactory(application)
}
return sInstance!!
}
}
}
3、生成自定義的ViewModel實(shí)例
//ViewModelProvider.kt
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
var viewModel = store[key]
if (modelClass.isInstance(viewModel)) {
(factory as? OnRequeryFactory)?.onRequery(viewModel)
return viewModel as T
} else {
@Suppress("ControlFlowWithEmptyBody")
if (viewModel != null) {
// TODO: log a warning.
}
}
viewModel = if (factory is KeyedFactory) {
factory.create(key, modelClass)
} else {
//此處進(jìn)入上一步創(chuàng)建好的AndroidViewModelFactory的create()方法中去
factory.create(modelClass)
}
store.put(key, viewModel)
return viewModel
}
//AndroidViewModelFactory 類
@Suppress("DocumentExceptions")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
try {
//1.第一步獲取自定義ViewModel的構(gòu)造器,第二部構(gòu)造viewmodel的實(shí)例
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)
}
4、ViewModel 觀察界面控制器的生命周期
在界面控制器的構(gòu)造函數(shù)中,就添加了對生命周期的觀察者,而當(dāng)觀察者收到當(dāng)前的界面控制器的生命周期是Lifecycle.Event.ON_DESTROY時(shí),就會將mViewModelStore對象map中所有保存的viewModel清理掉,這樣來達(dá)到釋放資源。
這里只處理了ON_DESTROY的生命周期狀態(tài),那么也就說明了在ViewModel對象實(shí)例創(chuàng)建成功后,不管界面控制器(如Activity)的生命周期(除ON_DESTROY外)如何發(fā)生變化,ViewModel都不會被清理掉。
//ComponentActivity.java
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.");
}
if (Build.VERSION.SDK_INT >= 19) {
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_STOP) {
Window window = getWindow();
final View decor = window != null ? window.peekDecorView() : null;
if (decor != null) {
decor.cancelPendingInputEvents();
}
}
}
});
}
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();
}
}
}
});
if (19 <= SDK_INT && SDK_INT <= 23) {
getLifecycle().addObserver(new ImmLeaksCleaner(this));
}
}
5、存儲ViewModel的數(shù)據(jù)結(jié)構(gòu)
//ViewModelStore.java
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
6、Hashmap存放ViewModel的key的生成規(guī)則
從這里看出來ViewModel對應(yīng)key的唯一性
//ViewModelProvider.kt
internal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"
public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
//這里需要注意下這個(gè)canonicalName是個(gè)什么東西
val canonicalName = modelClass.canonicalName
?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
return get("$DEFAULT_KEY:$canonicalName", modelClass)
}
//Class.java
public String getCanonicalName() {
if (isArray()) {
String canonicalName = getComponentType().getCanonicalName();
if (canonicalName != null)
return canonicalName + "[]";
else
return null;
}
if (isLocalOrAnonymousClass())
return null;
Class<?> enclosingClass = getEnclosingClass();
if (enclosingClass == null) { // top level class
return getName();
} else {
String enclosingName = enclosingClass.getCanonicalName();
if (enclosingName == null)
return null;
return enclosingName + "." + getSimpleName();
}
}
四、總結(jié)
ViewModel工作原理的核心技術(shù)點(diǎn):
觀察者模式、工程模式、反射、Hashmap數(shù)據(jù)結(jié)構(gòu)
ViewModel在MVVM架構(gòu)模型中,與DataBinding結(jié)合使用,會讓你有起飛的感覺。后續(xù)會進(jìn)一步加深使用。本篇僅以學(xué)會使用、了解原理為重點(diǎn)。