Andorid-JetPack-ViewModel組件用法和源碼解析

本文目標(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的時候會把ViewModelStoreFactory 都保存到成員變量中,那我們來看下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)建完畢,接下來看ViewModelProviderget()方法

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對象,就會把我們ViewModelclassName名字拼接上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是在ComponentActivityonRetainNonConfigurationInstance()方法中存儲的.
該方法中的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的父類ActivityretainNonConfigurationInstances()方法調(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í)行ActivityThreadhandleRelaunchActivity()方法,繼而調(diào)用retainNonConfigurationInstances()

我們都知道程序啟動的時候首先要調(diào)用ActivityThreadmain方法,
如果我們正常啟動一個activity的時候會調(diào)用ActivityThreadhandleLaunchActivity()方法,
如果是因為配置變更重新啟動一個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是存到ComponentActivityNonConfigurationInstances靜態(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:ViewModelonSaveIntanceState方法有什么區(qū)別呢?

  • 1.onSaveIntanceState只能存儲輕量級的key-value鍵值對數(shù)據(jù),非配置變更導(dǎo)致的頁面被回收時才會觸發(fā),此時數(shù)據(jù)存儲在ActivityRecord
  • 2.ViewModel可以存放任意Object數(shù)據(jù),因配置變更導(dǎo)致的頁面被回收才有效,此時存在ActivityThread#ActivityClientRecord
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末廊勃,一起剝皮案震驚了整個濱河市顿天,隨后出現(xiàn)的幾起案子正勒,更是在濱河造成了極大的恐慌蜻韭,老刑警劉巖悼尾,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肖方,居然都是意外死亡闺魏,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門俯画,熙熙樓的掌柜王于貴愁眉苦臉地迎上來析桥,“玉大人,你說我怎么就攤上這事艰垂∨菡蹋” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵材泄,是天一觀的道長沮焕。 經(jīng)常有香客問我,道長拉宗,這世上最難降的妖魔是什么峦树? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮旦事,結(jié)果婚禮上魁巩,老公的妹妹穿的比我還像新娘。我一直安慰自己姐浮,他們只是感情好谷遂,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卖鲤,像睡著了一般肾扰。 火紅的嫁衣襯著肌膚如雪畴嘶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天集晚,我揣著相機(jī)與錄音窗悯,去河邊找鬼。 笑死偷拔,一個胖子當(dāng)著我的面吹牛蒋院,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播莲绰,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼欺旧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛤签?” 一聲冷哼從身側(cè)響起辞友,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎顷啼,沒想到半個月后踏枣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡钙蒙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年茵瀑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躬厌。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡马昨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扛施,到底是詐尸還是另有隱情鸿捧,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布疙渣,位于F島的核電站匙奴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妄荔。R本人自食惡果不足惜泼菌,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望啦租。 院中可真熱鬧哗伯,春花似錦、人聲如沸篷角。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至虐块,卻和暖如春俩滥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背非凌。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工举农, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人敞嗡。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像航背,于是被迫代替她去往敵國和親喉悴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容