本文目標(biāo)
理解并掌握ViewModel組件用法和原理
1.什么是ViewModel
- 具備宿主生命周期感知能力的數(shù)據(jù)存儲組件
-
ViewModel
保存的數(shù)據(jù),在頁面因配置變更導(dǎo)致頁面銷毀重建之后依然是存在的
配置變更:橫豎屏切換权逗、分辨率調(diào)整请敦、權(quán)限變更、系統(tǒng)字體樣式變更...
ViewModel
是如何做到頁面銷毀了還能恢復(fù)期數(shù)據(jù)呢?
其實就是ViewModel
實例被保存了下來,頁面重建之后獲取的ViewModel
是同一個
2.基本用法
常規(guī)用法:存儲的數(shù)據(jù),僅僅只能當(dāng)頁面因為配置變更導(dǎo)致的銷毀再重建時可復(fù)用,復(fù)用的是ViewModel
的實例對象整體
public class MyGirlViewModel extends ViewModel {
//定義一個對象,相當(dāng)于一個用來存放數(shù)據(jù)的倉庫
private static MutableLiveData<List<Girl>> mLiveData;
/**
* 用于獲取數(shù)據(jù)
*/
public LiveData<List<Girl>> getDataList() {
if (mLiveData == null) {
mLiveData = new MutableLiveData<>();
loadData();
}
return mLiveData;
}
private void loadData() {
List<Girl> data = new ArrayList<>();
data.add(new Girl(R.drawable.f1, "一星", "****"));
data.add(new Girl(R.drawable.f2, "一星", "****"));
data.add(new Girl(R.drawable.f3, "一星", "****"));
data.add(new Girl(R.drawable.f4, "一星", "****"));
data.add(new Girl(R.drawable.f5, "一星", "****"));
data.add(new Girl(R.drawable.f6, "一星", "****"));
data.add(new Girl(R.drawable.f7, "一星", "****"));
data.add(new Girl(R.drawable.f8, "一星", "****"));
data.add(new Girl(R.drawable.f9, "一星", "****"));
data.add(new Girl(R.drawable.f10, "一星", "****"));
//把這些數(shù)據(jù)存到倉庫里
mLiveData.setValue(data);
}
//提供一個方法來改變數(shù)據(jù)
public void changeValue(int position, String value) {
//把數(shù)據(jù)取出來,然后更改其中某個條目的值,在把數(shù)據(jù)塞會倉庫里
List<Girl> list = mLiveData.getValue();
Girl girl = list.get(position);
girl.setLike(value);
mLiveData.setValue(list);
}
}
public class MainActivity extends AppCompatActivity {
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = findViewById(R.id.listview);
initListView();
}
private void initListView() {
MyGirlViewModel myGirlViewModel = new ViewModelProvider(this).get(MyGirlViewModel.class);
LiveData<List<Girl>> liveData = myGirlViewModel.getDataList();
//監(jiān)聽數(shù)據(jù)的改變,數(shù)據(jù)改變就會調(diào)用onChanged方法
liveData.observe(this, new Observer<List<Girl>>() {
/**
* 當(dāng)我們的數(shù)據(jù)發(fā)生變化的時候聪全,我們可以在這個onChanged中進(jìn)行處理
*/
@Override
public void onChanged(List<Girl> girls) {
Log.i("yd","onChanged刷新一次");
mListView.setAdapter(new GirlAdapter(MainActivity.this, girls));
}
});
mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
myGirlViewModel.changeValue(position,"哈哈哈哈哈哈哈哈哈");
return false;
}
});
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startActivity(new Intent(MainActivity.this,SecondActivity.class));
}
});
}
}
跨頁面數(shù)據(jù)共享
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
public void sendData(View view) {
//一定要在主線程中調(diào)用
MyGirlViewModel myGirlViewModel = new ViewModelProvider(this).get(MyGirlViewModel.class);
myGirlViewModel.changeValue(0,"我要改變的是第1條數(shù)據(jù)呀呀呀呀呀呀呀");
//必須是MainActivity 可見才能收到信息,如果不可見哪怕發(fā)送了信息也是收不到的
finish();
}
}
3.配置變更ViewModel復(fù)用實現(xiàn)原理
準(zhǔn)確點來說,應(yīng)該是ViewModel
如何做到在宿主銷毀了,還能繼續(xù)存在.以至于頁面恢復(fù)重建后,還能接著復(fù)用
肯定是前后獲取到的是同一個ViewModel
實例對象
我們先來看下獲取ViewModel
實例的過程
MyGirlViewModel myGirlViewModel = new ViewModelProvider(MainActivity.this).get(MyGirlViewModel.class);
ViewModelProvider
本質(zhì)是從傳遞進(jìn)去的ViewModelStore
來獲取實例,如果沒有,則利用factory
去創(chuàng)建
3.1 ViewModelProvider的創(chuàng)建
public class ViewModelProvider {
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
//把ViewModelStore 和 Factory 都保持到成員變量中
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
}
在創(chuàng)建ViewModelProvider
的時候需要傳參數(shù)ViewModelStoreOwner
,
我們的MainActivity
是繼承自頂層ComponentActivity
然后實現(xiàn)了ViewModelStoreOwner
接口的,所以我們可以直接傳MainActivity
,可以發(fā)現(xiàn)創(chuàng)建ViewModelProvider
的時候會把ViewModelStore
和 Factory
都保存到成員變量中,那我們來看下ViewModelStore
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
中就是封裝了個HashMap
,用來存儲ViewModel
然后我們來看下 Factory
,該工廠就是創(chuàng)造ViewModel
用的
public interface Factory {
/**
* Creates a new instance of the given {@code Class}.
* <p>
*
* @param modelClass a {@code Class} whose instance is requested
* @param <T> The type parameter for the ViewModel.
* @return a newly created ViewModel
*/
@NonNull
<T extends ViewModel> T create(@NonNull Class<T> modelClass);
}
就是說,當(dāng)我們來獲取ViewModel
實例的時候,如果在ViewModelStore
中獲取不到,就會用Factory
去創(chuàng)造一個實例,
ok,到這里ViewModelProvider
對象已經(jīng)創(chuàng)建完畢,接下來看ViewModelProvider
的get()
方法
3.2 ViewModelProvider調(diào)用get()方法
public class ViewModelProvider {
private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//1.從mViewModelStore中根據(jù)key去找ViewModel
ViewModel viewModel = mViewModelStore.get(key);
//2.判斷viewModel該實例是不是我們傳入的modelClass類型的
if (modelClass.isInstance(viewModel)) {
if (mFactory instanceof OnRequeryFactory) {
((OnRequeryFactory) mFactory).onRequery(viewModel);
}
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//3.如果不是就通過工廠來創(chuàng)建一個viewModel實例
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
//4.創(chuàng)建完成之后存到mViewModelStore 的 map中
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
}
當(dāng)調(diào)用get()
方法的時候,我們只是傳遞了一個ViewModel
的.class
對象,就會把我們ViewModel
的className
名字拼接上DEFAULT_KEY
作為Key
,
這就是在ViewModelStore
中存儲的Key
,Value
是我們的ViewModel
的.class
對象
我們知道了ViewModel
是從ViewModelStore
中獲取的,那既然想做到ViewModel
實例的復(fù)用,那就是說ViewModelStore
也要復(fù)用,關(guān)鍵點就在這里
3.3 ViewModelStore
是在哪里獲取的?
通過看ViewModelProvider
的構(gòu)造方法,我們可以發(fā)現(xiàn)是在owner.getViewModelStore()
中獲取的
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
追進(jìn)去發(fā)現(xiàn),owner.getViewModelStore()
這行代碼是在ComponentActivity
中實現(xiàn)的,
也就是說ViewModelStore
是在ComponentActivity
中獲取的
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
//保存用來配置變更后還想保存的數(shù)據(jù)
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
@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.");
}
if (mViewModelStore == null) {
//1.viewModelStore是根據(jù)getLastNonConfigurationInstance()獲取的
NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
//2.從NonConfigurationInstances中把viewModelStore提出來變成成員變量
mViewModelStore = nc.viewModelStore;
}
//3.如果mViewModelStore為空,則就創(chuàng)建一個
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
}
在ComponentActivity
中的getViewModelStore
方法中我們發(fā)現(xiàn)
- 1.
viewModelStore
是根據(jù)getLastNonConfigurationInstance()
獲取的 - 2.從
NonConfigurationInstances
中把viewModelStore
提出來變成成員變量 - 3.如果
mViewModelStore
為空,則就創(chuàng)建一個
那這個只是ViewModelStore
的獲取,那我們想知道ViewModelStore
是在什么地方存的呢?
3.3 ViewModelStore
是在哪里存儲的?
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
LifecycleOwner,
ViewModelStoreOwner,
SavedStateRegistryOwner,
OnBackPressedDispatcherOwner {
//保存用來配置變更后還想保存的數(shù)據(jù)
static final class NonConfigurationInstances {
Object custom;
ViewModelStore viewModelStore;
}
//什么時候被觸發(fā)呢?
//是在`Activity`的`retainNonConfigurationInstances()`方法調(diào)用的
@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
//如果我們想在activity保存一下數(shù)據(jù),就是說因配置變更頁面被銷毀了,重建的時候繼續(xù)復(fù)用
//我們就可以重寫onRetainCustomNonConfigurationInstance()這個方法,然后獲取的時候可以用getLastNonConfigurationInstance()
//不過這種方式已經(jīng)被廢棄掉了,了解即可,現(xiàn)在都推薦使用ViewModel
Object custom = onRetainCustomNonConfigurationInstance();
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
//如果viewModelStore 為空則就直接 return 空了
if (viewModelStore == null && custom == null) {
return null;
}
//如果viewModelStore 不為空,就創(chuàng)建NonConfigurationInstances對象并把viewModelStore存進(jìn)去
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
nci.viewModelStore = viewModelStore;
return nci;
}
}
ViewModelStore
是在ComponentActivity
的onRetainNonConfigurationInstance()
方法中存儲的.
該方法中的onRetainCustomNonConfigurationInstance()
這行代碼,
如果我們想在activity
保存一下數(shù)據(jù),就是說因配置變更頁面被銷毀了,重建的時候繼續(xù)復(fù)用
我們就可以重寫onRetainCustomNonConfigurationInstance()
這個方法,然后獲取的時候可以用getLastNonConfigurationInstance()
不過這種方式已經(jīng)被廢棄掉了,了解即可,現(xiàn)在都推薦使用ViewModel
小總結(jié)一下:
我們已經(jīng)知道了ViewModelStore
是在onRetainNonConfigurationInstance()
方法中存儲的,
但是我們要知道onRetainNonConfigurationInstance()
在什么情況下才會被調(diào)用,
只有這個方法調(diào)用了,我們的ViewModelStore
才能存到NonConfigurationInstances
中,這才能實現(xiàn)復(fù)用
3.4 onRetainNonConfigurationInstance()
方法又是在哪被調(diào)用的呢?
是在ComponentActivity
的父類Activity
的retainNonConfigurationInstances()
方法調(diào)用的
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback,
AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
//該方法又是在哪里調(diào)用的呢?是在ActivityTread中調(diào)用的
NonConfigurationInstances retainNonConfigurationInstances() {
//調(diào)用該方法
Object activity = onRetainNonConfigurationInstance();
......
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.activity = activity;
nci.children = children;
nci.fragments = fragments;
nci.loaders = loaders;
if (mVoiceInteractor != null) {
mVoiceInteractor.retainInstance();
nci.voiceInteractor = mVoiceInteractor;
}
return nci;
}
public Object onRetainNonConfigurationInstance() {
return null;
}
}
那retainNonConfigurationInstances()
方法又是在哪里調(diào)用的呢?答案是在ActivityThread
中被調(diào)用的,
3.4 因配置變更重新啟動一個activity
,會執(zhí)行ActivityThread
的handleRelaunchActivity()
方法,繼而調(diào)用retainNonConfigurationInstances()
我們都知道程序啟動的時候首先要調(diào)用ActivityThread
的main
方法,
如果我們正常啟動一個activity
的時候會調(diào)用ActivityThread
的handleLaunchActivity()
方法,
如果是因為配置變更重新啟動一個activity
的時候,是走的handleRelaunchActivity()
方法,
這里先告訴大家,retainNonConfigurationInstances()
方法是在handleRelaunchActivity()
中的handleDestroyActivity()
方法中的performDestroyActivity()
方法中調(diào)用的,具體源碼如下
public final class ActivityThread extends ClientTransactionHandler {
final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
public static final class ActivityClientRecord {
//這個字段存儲的就是因配置變更導(dǎo)致的被銷毀的那個activity存留下來的數(shù)據(jù)
Activity.NonConfigurationInstances lastNonConfigurationInstances;
}
//正常啟動一個activity會走這個方法
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {
..........
}
//1.因為配置變更重新啟動一個`activity`的時候會調(diào)用這個方法
@Override
public void handleRelaunchActivity(ActivityClientRecord tmp,PendingTransactionActions pendingActions) {
.....
//mActivities這個集合存儲的是當(dāng)前app已經(jīng)打開的所有activity
ActivityClientRecord r = mActivities.get(tmp.token);
handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
.....
}
//2.因為配置變更重新啟動一個`activity`的時候會調(diào)用這個方法
private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
PendingTransactionActions pendingActions, boolean startsNotResumed,
Configuration overrideConfig, String reason) {
final Intent customIntent = r.activity.mIntent;
//重新創(chuàng)建一個activity之前要把發(fā)生配置變更的activity銷毀
if (!r.paused) {
performPauseActivity(r, false, reason, null /* pendingActions */);
}
if (!r.stopped) {
callActivityOnStop(r, true /* saveState */, reason);
}
//該方法的第4個參數(shù)getNonConfigInstance,這里面?zhèn)鞯氖莟rue
//經(jīng)過這個方法后,ActivityClientRecord 這個r對象就包含了那個被銷毀的activity所存留下來的對象
handleDestroyActivity(r.token, false, configChanges, true, reason);
......
//重新打開一個新的activity
handleLaunchActivity(r, pendingActions, customIntent);
}
//重要方法,經(jīng)過這個方法后,ActivityClientRecord 這個r對象就包含了那個被銷毀的activity所存留下來的對象
@Override
public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,boolean getNonConfigInstance, String reason) {
ActivityClientRecord r = performDestroyActivity(token, finishing,configChanges, getNonConfigInstance, reason);
}
//該方法是真正執(zhí)行Activity的destroy方法的
ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,int configChanges, boolean getNonConfigInstance, String reason) {
ActivityClientRecord r = mActivities.get(token);
if (getNonConfigInstance) {//此處為true
//該行代碼就會調(diào)用activity的retainNonConfigurationInstances方法,
//從而把Activity受到配置變更而不想丟失的數(shù)據(jù)給保存起來,那我們的viewModelStore對象也就被保存起來了
r.lastNonConfigurationInstances= r.activity.retainNonConfigurationInstances();
}
return r;
}
}
1.當(dāng)一個
activity
重建的時候就會執(zhí)行ActivityThread
中的handleRelaunchActivity()
,然后會經(jīng)過一系列調(diào)用,
handleRelaunchActivity()
--->handleDestroyActivity()
--->performDestroyActivity()
--->r.activity.retainNonConfigurationInstances();
2.
retainNonConfigurationInstances()方法
,作用就是把Activity
受到配置變更而不想丟失的數(shù)據(jù)給保存起來,那我們的viewModelStore
對象也就被保存起來了,數(shù)據(jù)都會存在ActivityClientRecord
中,其中有個字段Activity.NonConfigurationInstances lastNonConfigurationInstances
,這個字段存儲的就是因配置變更導(dǎo)致的被銷毀的那個activity
存留下來的數(shù)據(jù)3.當(dāng)
handleDestroyActivity()
這個方法被調(diào)用完,我們的ActivityClientRecord
這個r對象
就包含了那個被銷毀的activity
所存留下來的數(shù)據(jù),最后會調(diào)用handleLaunchActivity()
重新打開一個activity
,接下來handleLaunchActivity()
中就調(diào)用performLaunchActivity()
方法
3.5handleLaunchActivity
方法創(chuàng)建新的Activity
并啟動
public final class ActivityThread extends ClientTransactionHandler {
//正常啟動一個activity會走這個方法
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {
final Activity a = performLaunchActivity(r, customIntent);
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
//1.新建一個activity
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
}
//2.執(zhí)行attach方法把r.lastNonConfigurationInstances傳進(jìn)去了
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);
}
}
- 1.不難發(fā)現(xiàn),在
performLaunchActivity()
方法中會通過newActivity()
的形式創(chuàng)建activity
- 2.執(zhí)行
attach
方法把r.lastNonConfigurationInstances
傳進(jìn)去了
3.6Activity
最終把lastNonConfigurationInstances
對象保存了起來
public class Activity{
@UnsupportedAppUsage
NonConfigurationInstances mLastNonConfigurationInstances;
@UnsupportedAppUsage
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) {
//保存了起來
mLastNonConfigurationInstances = lastNonConfigurationInstances;
}
@Nullable
public Object getLastNonConfigurationInstance() {
return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null;
}
}
所以在getLastNonConfigurationInstance()
方法中能拿到mLastNonConfigurationInstances
對象,那我們就能拿到我們的ViewModelStore
,從而完成我們實例對象的復(fù)用
總結(jié)
問題1:ViewModel
是如何實現(xiàn)因配置變更還能還原數(shù)據(jù)的呢?
準(zhǔn)確點來說,應(yīng)該是ViewModel
如何做到在宿主銷毀了,還能繼續(xù)存在.以至于頁面恢復(fù)重建后,還能接著復(fù)用
- 1.首先我們的
ViewModel
是存到ViewModelStore
中的HashMap
中,然后我們這個ViewModelStore
是存到ComponentActivity
的NonConfigurationInstances
靜態(tài)內(nèi)部類中 - 2.當(dāng)我們的
Activity
因為配置變更發(fā)生改變的時候,會調(diào)用ActivityThread
中的handleRelaunchActivity
,這里面有個handleDestroyActivity()
執(zhí)行完這個方法后,就把Activity
受到配置變更而不想丟失的數(shù)據(jù)給保存起來,那我們的viewModelStore
對象也就被保存起來了 - 3.繼而繼續(xù)調(diào)用
handleLaunchActivity
方法創(chuàng)建新的Activity
并啟動
問題2:ViewModel
和onSaveIntanceState
方法有什么區(qū)別呢?
- 1.
onSaveIntanceState
只能存儲輕量級的key-value
鍵值對數(shù)據(jù),非配置變更導(dǎo)致的頁面被回收時才會觸發(fā),此時數(shù)據(jù)存儲在ActivityRecord
中 - 2.
ViewModel
可以存放任意Object
數(shù)據(jù),因配置變更導(dǎo)致的頁面被回收才有效,此時存在ActivityThread#ActivityClientRecord
中