一旗唁、介紹
ViewModel就是存儲(chǔ)頁(yè)面相關(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ù)分離出來(lái)诸衔,這樣這樣界面控制器就主要負(fù)責(zé)與UI相關(guān)的事情即可)
加大保存數(shù)據(jù)的范圍(當(dāng)頁(yè)面發(fā)送無(wú)意關(guān)閉時(shí)盯漂,我們一般是onSaveInstanceState()來(lái)保存數(shù)據(jù)颇玷,但是這樣保存的數(shù)據(jù)大小有限制,而且是必須可序列化再反序列化的數(shù)據(jù)就缆,而viewmodel可以保存我們頁(yè)面所需的所有數(shù)據(jù))
分離界面控制器的工作(將一些與數(shù)據(jù)相關(guān)的業(yè)務(wù)處理分來(lái)出來(lái)帖渠,減少控制器對(duì)業(yè)務(wù)的處理工作)
ViewModel 保存的數(shù)據(jù)會(huì)在activity完成時(shí),由框架調(diào)用onCleared方法清理資源
ViewModel的生命周期
在viewModel對(duì)象創(chuàng)建時(shí)開(kāi)始竭宰,一直到他所關(guān)聯(lián)的界面控制器銷毀時(shí)才銷毀空郊,這就說(shuō)明了即使發(fā)生了橫豎屏切換,界面相關(guān)的數(shù)據(jù)也是一直存在并且不受橫豎屏切換的影響切揭。
通常我們是在Actvity的onCreate()方法中來(lái)創(chuàng)建ViewModel對(duì)象狞甚,該ViewModel對(duì)象會(huì)一直在內(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涩盾、 簡(jiǎn)單使用
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來(lái)使用ViewModel的數(shù)據(jù)的
viewModel.position.observe(this,{
Log.e(TAG, "onCreate: position value = ${it}")
})
}
}
三、工作原理
原理:
當(dāng)開(kāi)始創(chuàng)建Activity的實(shí)例對(duì)象時(shí)励背,會(huì)生成用來(lái)存儲(chǔ)ViewModel對(duì)象的ViewModelStore實(shí)例(使用Hashmap數(shù)據(jù)結(jié)構(gòu)存儲(chǔ))春霍,并給當(dāng)前Activity的生命周期添加觀察者,用于觀察Activity的生命周期變化叶眉,當(dāng)Activity的生命周期是ON_DESTROY時(shí)址儒,就會(huì)清理掉ViewModelStore中存儲(chǔ)的ViewModel的所有對(duì)象,釋放資源衅疙。
創(chuàng)建ViewModelProvider對(duì)象實(shí)例時(shí)莲趣,會(huì)在其構(gòu)造中調(diào)用生成一個(gè)AndroidViewModelFactory的全局工程對(duì)象,我們會(huì)使用這個(gè)工廠對(duì)象來(lái)反射自定義的ViewModel對(duì)象炼蛤。
當(dāng)使用ViewModelProvider對(duì)象實(shí)例get自定義的ViewModel對(duì)象時(shí)妖爷,會(huì)先從ViewModelStore的Hashmap去找,如果沒(méi)有找到理朋,就用上一步的AndroidViewModelFactory實(shí)例來(lái)反射自定義的ViewModel對(duì)象絮识,并將該ViewModel保存到Hashmap中,下次使用的時(shí)候就可以直接使用嗽上;如果找了ViewModel 就直接返回該ViewModel的對(duì)象次舌。
從上面ViewModel的工作原理可以得知:
1、ViewModel 一旦創(chuàng)建好了兽愤,就會(huì)一直保存到當(dāng)前界面控制器(Activity 彼念、Fragment等)銷毀時(shí)才會(huì)釋放資源挪圾;
2、不同的界面控制器逐沙,ViewModel 的對(duì)象時(shí)存在不同的Hashmap中的哲思,他們也是不同的對(duì)象;局部單例吩案;
3棚赔、要做到全局單例ViewModel對(duì)象,可以將ViewModel放到Application中去徘郭;
接下來(lái)從源碼角度來(lái)分析一下原理:
1靠益、創(chuàng)建存儲(chǔ)ViewModel的容器ViewModelStore對(duì)象
在構(gòu)建Activity的對(duì)象時(shí),在其父類ComponentActivity.java中實(shí)現(xiàn)了接口ViewModelStoreOwner残揉,在其實(shí)現(xiàn)方法中生成ViewModelStore對(duì)象
//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工廠對(duì)象
//ViewModelProvider.kt
public constructor(
owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner))
//AndroidViewModelFactory的伴生對(duì)象
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對(duì)象
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ù)中,就添加了對(duì)生命周期的觀察者江醇,而當(dāng)觀察者收到當(dāng)前的界面控制器的生命周期是Lifecycle.Event.ON_DESTROY時(shí)濒憋,就會(huì)將mViewModelStore對(duì)象map中所有保存的viewModel清理掉,這樣來(lái)達(dá)到釋放資源陶夜。
這里只處理了ON_DESTROY的生命周期狀態(tài)凛驮,那么也就說(shuō)明了在ViewModel對(duì)象實(shí)例創(chuàng)建成功后,不管界面控制器(如Activity)的生命周期(除ON_DESTROY外)如何發(fā)生變化条辟,ViewModel都不會(huì)被清理掉黔夭。
//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、存儲(chǔ)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ī)則
從這里看出來(lái)ViewModel對(duì)應(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é)合使用魂爪,會(huì)讓你有起飛的感覺(jué)先舷。后續(xù)會(huì)進(jìn)一步加深使用。本篇僅以學(xué)會(huì)使用滓侍、了解原理為重點(diǎn)蒋川。