Android ViewModel的作用深入講解
ViewModel它的作用是什么呢
ViewModel 類旨在以注重生命周期的方式存儲和管理界面相關(guān)數(shù)據(jù)。ViewModel 類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存(官方解釋)
看到這里我們就可以總結(jié)viewmodel的兩個(gè)作用點(diǎn),第一viewmodel在activity和fragment銷毀時(shí)自己也會被清除掉,第二點(diǎn)viewmodel在屏幕旋轉(zhuǎn)activity銷毀后重建可以顯示之前數(shù)據(jù)。
那么問題就來了viewmodel是怎么保存數(shù)據(jù)的以及自動釋放掉內(nèi)存? 這兩個(gè)問題弄懂了viewmodel的面紗也就被我們揭開了。
那我們就直接從最簡單的使用viewmodel開始說起
class UserViewModel : ViewModel() {
var age: Int = 0
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val userViewModel =
ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())[UserViewModel::class.java]
val mView = ActivityMainBinding.inflate(layoutInflater)
setContentView(mView.root)
mView.tv.text = userViewModel.age.toString()
var sum = 0
mView.tv.setOnClickListener {
sum = sum.inc()
userViewModel.age = sum
}
}
}隨著我們不停的點(diǎn)擊 sum會越來越大 當(dāng)我們旋轉(zhuǎn)屏幕的時(shí)候 activity會重建 但是我們獲取的age卻是最后一次點(diǎn)擊的值,這就證明了我們數(shù)據(jù)是被保存了下來。那么viewmodel是怎么做到的呢?我們從源碼角度去分析
以下源碼分析是從Android13分析的
看源碼viewmodel是一個(gè)抽象類,并不能看出什么。那么我們就得換一個(gè)思路去思考了。既然viewmodel是和activity有關(guān)系,而且在activity旋轉(zhuǎn)銷毀時(shí)還能做到復(fù)用,那么我們就從activity中去尋找。
一級一級尋找發(fā)現(xiàn)在ComponentActivity實(shí)現(xiàn)了一個(gè)ViewModelStoreOwner接口 看命名是和viewmodel有點(diǎn)關(guān)系看下這個(gè)接口內(nèi)部有什么
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
//代碼很簡潔 一個(gè)抽象方法 返回值ViewModelStore 顧名思義這個(gè)類的功能也就呼之欲出,存儲viewmodel,那我們就看實(shí)現(xiàn)類中怎么處理的
//ComponentActivity中實(shí)現(xiàn)
@NonNull
@Override
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
ensureViewModelStore();
return mViewModelStore;
}
//我們直接看ensureViewModelStore()方法
void ensureViewModelStore() {
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
}
//ensureViewModelStore方法看來是為了獲取ViewModelStore,那我們在具體看下ViewModelStore內(nèi)部做了什么?
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();
}
}
//看到這里就明了了,果然和我們猜想的一樣,ViewModelStore是用來緩存ViewModel的經(jīng)過我們分析已經(jīng)明白了viewmodel是被ViewModelStore緩存起來的,那么又是如何做到在activity不正常銷毀時(shí)去恢復(fù)數(shù)據(jù)的呢?
在ComponentActivity在發(fā)現(xiàn)還有另一個(gè)方法中使用了ViewModelStore
onRetainNonConfigurationInstance方法
public final Object onRetainNonConfigurationInstance() {
// Maintain backward compatibility.
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}方法體內(nèi)的代碼也很容易理解 如果viewModelStore為null 就去給它賦值。那么這個(gè)方法是在什么時(shí)候執(zhí)行的呢?經(jīng)過一番debug發(fā)現(xiàn)在activity切換橫豎屏的時(shí)候 這個(gè)方法就被觸發(fā)了 而getViewModelStore方法在activity創(chuàng)建的時(shí)候就執(zhí)行了。我們現(xiàn)在知道了viewModelStore的創(chuàng)建時(shí)機(jī),那么viewmodel是如何存儲到viewModelStore中的呢?
還記得我們寫的示例代碼嗎?
val userViewModel =
ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
.get(UserViewModel::class.java)我們就從ViewModelProvider入手
public constructor(owner: ViewModelStoreOwner, factory: Factory) : this(
owner.viewModelStore,
factory,
defaultCreationExtras(owner)
)第一個(gè)入?yún)⒕褪俏覀僡ctivity實(shí)例 然后拿到我們自己的viewModelStore,這個(gè)時(shí)候的viewModelStore已經(jīng)創(chuàng)建好了,看第二個(gè)參數(shù)是Factory 我們傳遞的是NewInstanceFactory這個(gè)一看就是單例,內(nèi)部實(shí)現(xiàn)了一個(gè)create方法
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)
}
}一個(gè)泛型方法返回一個(gè)自定義的viewmodel實(shí)例,但是還是沒看到如何存儲的viewmodel,別急
我們再來看最后調(diào)用的get方法
@MainThread
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
val 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.
}
}
val extras = MutableCreationExtras(defaultCreationExtras)
extras[VIEW_MODEL_KEY] = key
// AGP has some desugaring issues associated with compileOnly dependencies so we need to
// fall back to the other create method to keep from crashing.
return try {
factory.create(modelClass, extras)
} catch (e: AbstractMethodError) {
factory.create(modelClass)
}.also { store.put(key, it) }
}首選會從ViewModelStore中獲取viewmodel ,看if語句內(nèi)部就可以看出直接返回的是緩存的viewmodel,如果不存在則根據(jù)創(chuàng)建的factory去實(shí)例化viewmodel然后并存儲到ViewModelStore中。
經(jīng)過我們的源碼分析,我們現(xiàn)在已經(jīng)明白了viewmodel的存儲過程和如何在activity銷毀時(shí)獲取的流程。
那么viewmodel又是如何銷毀的呢?還記得viewmodel中的onCleared方法嗎?注釋就寫明了當(dāng)這個(gè)ViewModel不再使用并被銷毀時(shí),這個(gè)方法將被調(diào)用。 那么就來看這個(gè)方法在什么時(shí)候調(diào)用的
內(nèi)部有一個(gè)clear該方法又被ViewModelStore的clear方法調(diào)用,接著又被ComponentActivity內(nèi)部
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()) {
getViewModelStore().clear();
}
}
}
});用到了Lifecycle去監(jiān)聽生命周期當(dāng)activity不正常銷毀時(shí),則清除掉緩存的viewmodel。至此我們就搞懂了viewmodel是如何實(shí)現(xiàn)了對數(shù)據(jù)的存儲和以及數(shù)據(jù)的獲取。
這里還有一點(diǎn)需要額外說明,ViewModelStore也是從緩存中取得, 在getViewModelStore方法和onRetainNonConfigurationInstance方法中 都能看到getLastNonConfigurationInstance方法的身影。不為null,就獲取緩存的ViewModelStore,那就自然能獲取到之前存儲的viewModel 至于怎么緩存的各位大佬自己研究吧!
至此 ,我們已經(jīng)搞懂了viewmodel是如何做到在activity銷毀時(shí)自動清除和銷毀重建顯示之前數(shù)據(jù)。
到此這篇關(guān)于Android ViewModel的作用深入講解的文章就介紹到這了,更多相關(guān)Android ViewModel內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android實(shí)現(xiàn)底部導(dǎo)航欄功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)底部導(dǎo)航欄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
Android實(shí)現(xiàn)編程修改手機(jī)靜態(tài)IP的方法
這篇文章主要介紹了Android實(shí)現(xiàn)編程修改手機(jī)靜態(tài)IP的方法,涉及Android編程實(shí)現(xiàn)對系統(tǒng)底層信息修改的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
淺談Android輕量級的數(shù)據(jù)緩存框架RxCache
本篇文章主要介紹了淺談Android輕量級的數(shù)據(jù)緩存框架RxCache,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
Android使用CardView作為RecyclerView的Item并實(shí)現(xiàn)拖拽和左滑刪除
這篇文章主要介紹了Android使用CardView作為RecyclerView的Item并實(shí)現(xiàn)拖拽和左滑刪除,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
Android中的Selector的用法詳解及實(shí)例
這篇文章主要介紹了Android中的Selector的用法詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-05-05

