Android Jetpack 架構(gòu)組件之 ViewModel 源碼分析

Android Jetpack 架構(gòu)組件之 ViewModel 源碼分析

1. 認(rèn)識 ViewModel

1.1. ViewModel 是什么

引用官方介紹:
ViewModel 被設(shè)計(jì)成以生命周期感知的方式去存儲和管理和 UI 相關(guān)的數(shù)據(jù)。ViewModel 類允許諸如屏幕旋轉(zhuǎn)等配置改變之后繼續(xù)保存數(shù)據(jù)咨油。它使得從 UI Controller (Activity 或 Fragment)將 View 的數(shù)據(jù)分離出來變得更加的容易且高效晦款。

1.2. ViewModel 的優(yōu)勢

  1. 職責(zé)單一梨树,主要是存儲和對 UI 數(shù)據(jù)進(jìn)行管理捌议。
  2. 具有生命周期感知能力青扔,當(dāng) Activity 的 ON_DESTROYED 生命周期事件被分發(fā)了映皆,并且不是系統(tǒng)配置發(fā)生改變的情況下租幕,才會銷毀當(dāng)前 頁面中 ViewModelStoreOwner 所有 ViewModel 對象腊嗡。
  3. 支持 coroutine着倾。
  4. 支持同一個(gè) Activity 下的多個(gè) Fragments 頁面之間共用同一個(gè) ViewModel,并使用 LiveData 來進(jìn)行數(shù)據(jù)的共享燕少。
  5. 能夠和 LiveData卡者,Room 配置來實(shí)現(xiàn)非常優(yōu)雅的數(shù)據(jù)庫操作。

1.3. 傳統(tǒng)數(shù)據(jù)管理存在的問題

在以往的操作中客们,我們一般會把數(shù)據(jù)直接寫在頁面對象中(如:Activity崇决,F(xiàn)ragment),而當(dāng) configuration 配置發(fā)生改變的時(shí)候底挫,頁面對象被重建恒傻,之前緩存在業(yè)務(wù)的數(shù)據(jù)已經(jīng)被回收。如果我們要保存數(shù)據(jù)的話建邓,需要在 onSaveInstanceState() 回調(diào)方法中進(jìn)行數(shù)據(jù)的保存盈厘,然后,在重建的 Activity 的 onCreate() 回調(diào)方法中進(jìn)行數(shù)據(jù)的huifu恢復(fù)官边。這顯然會增加開發(fā)人員的工作量沸手,而且稍不注意就會漏寫。

又或者在以往的 MVP注簿,MVVM 等架構(gòu)中將數(shù)據(jù)保存在了 Presenter 層或者 ViewModel 層(非官方提供的)契吉,而當(dāng) Activity 由于屏幕旋轉(zhuǎn)等被銷毀重建后,如果沒有做特殊的處理诡渴,被重建的 Activity 又會去綁定新的 Presenter 或 ViewModel 對象捐晶,等于說還是沒有很好的起到保存數(shù)據(jù)的作用。

2. ViewModel 結(jié)構(gòu)及各自職責(zé)

2.1. ViewModel 類關(guān)系圖

image

2.2. ViewModel 各自職責(zé)

根據(jù)上圖我們來對其中的主要的幾個(gè)類在整個(gè)實(shí)現(xiàn)中所起到的作用做一個(gè)說明。

1. ViewModelProvider

public class ViewModelProvider {
private static final String DEFAULT_KEY =
        "androidx.lifecycle.ViewModelProvider.DefaultKey";
private final Factory mFactory;
private final ViewModelStore mViewModelStore;

    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);
}

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
ViewModel viewModel = mViewModelStore.get(key);

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.
    }
}
if (mFactory instanceof KeyedFactory) {
    viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
    viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}

......

ViewModelProvider 其實(shí)是一個(gè) ViewModel 的管理類租悄,主要負(fù)責(zé)存儲和獲取 ViewModel 對象谨究。所有的 ViewModel 對象都是通過這個(gè)類來進(jìn)行獲取的。ViewModelProvider 依賴于兩個(gè)對象泣棋,一個(gè)是 ViewModelStore 對象胶哲,用于實(shí)際存儲 ViewModel 對象,另外一個(gè)是具體創(chuàng)建 ViewModel 的工廠類 Factory 及其實(shí)現(xiàn)潭辈。

其核心的方法只有一個(gè)就是 get(@NonNull String key, @NonNull Class<T> modelClass) 方法鸯屿,用于通過 ViewModel 的 Key 來獲取到當(dāng)前頁面所對應(yīng)的 ViewModelStore 中所存儲的 ViewModel 對象。

ViewModelProvider 這里其實(shí)沒有并沒有將 ViewModel put 進(jìn)去的方法把敢,你只需要通過實(shí)現(xiàn)了 ViewModel 的 Class 類對象直接來獲取就可以了寄摆,如果在緩存中沒有找到,就會直接將其裝入緩存并將其 ViewModel 的實(shí)例對象返回修赞。

另外婶恼,這里還有一個(gè) get(@NonNull Class<T> modelClass) 方法,當(dāng)我們在獲取 ViewModel 的過程中柏副,沒有指定 Key 的話勾邦,ViewModelProvider 會為我們設(shè)置一個(gè)默認(rèn)的可以唯一區(qū)別于其它 ViewModel 的 key 作為默認(rèn)的 key。

還有一點(diǎn)是割择,這里對 ViewModel 的類對象作了嚴(yán)格的限定眷篇,必須是具有 canonical name 的類對象。哪些類對象是沒有 canonical name 的呢荔泳?主要是:內(nèi)部類蕉饼,匿名內(nèi)部類和數(shù)組。后兩種基本上不會碰到玛歌,但是內(nèi)部類還是有可能出現(xiàn)的昧港,所以,在開發(fā)的時(shí)候要注意一下支子。

2. SavedStateViewModelFactory

public final class SavedStateViewModelFactory extends ViewModelProvider.KeyedFactory {
    private final Application mApplication;
    private final ViewModelProvider.AndroidViewModelFactory mFactory;
    private final Bundle mDefaultArgs;
    private final Lifecycle mLifecycle;
    private final SavedStateRegistry mSavedStateRegistry;
    
    .......
        @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if (isAndroidViewModel) {
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            // 如果要創(chuàng)建的 ViewModel 不是 AndroidViewModel 
            // 的話默認(rèn)情況下會走這里慨飘,而如果所要創(chuàng)建的 ViewModel 中沒有
            // 只有一個(gè) SavedStateHandle 參數(shù)的構(gòu)造函數(shù)的話,這里的   
            // constructor 會為 null
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
            // 這里調(diào)用的是 AndroidViewModelFactory 的 create 方法
            return mFactory.create(modelClass);
        }

        // 走到這里說明我們要創(chuàng)建的 ViewModel 中有一個(gè)帶有 SavedStateHandle // 的構(gòu)造函數(shù)译荞,上面的 constructor 不為空。這里的 controller 
        // 實(shí)際上是一個(gè)保存 SaveState 信息及頁面事件監(jiān)聽的控制器休弃,用于保存頁面數(shù)據(jù)及根據(jù)生命周期事件來對自己進(jìn)行管理
        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if (isAndroidViewModel) {
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
            return viewmodel;
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Failed to access " + modelClass, e);
        } catch (InstantiationException e) {
            throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException("An exception happened in constructor of "
                    + modelClass, e.getCause());
        }
    }
    ......
}

SavedStateViewModelFactory 是 ViewModel 組件提供的一個(gè)默認(rèn)的創(chuàng)建 ViewModel 的實(shí)現(xiàn)類吞歼。當(dāng)我們通過 ViewModelProvider 獲取 ViewModel 時(shí),如果沒有指定具體用哪個(gè)一工廠去創(chuàng)建的話塔猾,系統(tǒng)默認(rèn)使用當(dāng)前傳入的 ViewModelStoreOwner(主要是 Activity 和 Fragment) 中所實(shí)現(xiàn)了 getDefaultViewModelProviderFactory() 方法去獲取默認(rèn)的 Factory篙骡,而這個(gè)默認(rèn)的 Factory 就是 SavedStateViewModelFactory。

SavedStateViewModelFactory 的作用主要是用于創(chuàng)建可以保存當(dāng)前頁面的數(shù)據(jù)的 ViewModel。也就是說當(dāng)我們的頁面數(shù)據(jù)還是保存在頁面的時(shí)候糯俗,我們可以通過該默認(rèn)工廠尿褪,把頁面的數(shù)據(jù)存儲到由 SavedStateViewModelFactory 所創(chuàng)建的 ViewModel 中進(jìn)行保存。前提是:需要我們的 ViewModel 的最終實(shí)現(xiàn)類的構(gòu)造方法簽名和下面的 ANDROID_VIEWMODEL_SIGNATURE 或 VIEWMODEL_SIGNATURE 一樣才會起到上面說的效果得湘,否則杖玲,就會調(diào)用 AndroidViewModelFactory 中的 create() 方法去創(chuàng)建 ViewModel 對象

class SaveStateViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() {

}

private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class[]{Application.class,
            SavedStateHandle.class};
private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class[]{SavedStateHandle.class};

當(dāng)然這里還有一點(diǎn)需要注意的是:你必須在 Activity 或 Fragment 的對應(yīng)回調(diào)函數(shù) onSaveInstanceState() 中對數(shù)據(jù)進(jìn)行了存儲才有意義的淘正。

3. SavedStateHandleController

final class SavedStateHandleController implements LifecycleEventObserver {
    private final String mKey;
    private boolean mIsAttached = false;
    private final SavedStateHandle mHandle;
    
    ....
    
    void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
        if (mIsAttached) {
            throw new IllegalStateException("Already attached to lifecycleOwner");
        }
        mIsAttached = true;
        lifecycle.addObserver(this);
        registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
    }
    
    static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
        String key, Bundle defaultArgs) {
        Bundle restoredState = registry.consumeRestoredStateForKey(key);
        SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
        SavedStateHandleController controller = new SavedStateHandleController(key, handle);
        controller.attachToLifecycle(registry, lifecycle);
        tryToAddRecreator(registry, lifecycle);
        return controller;
    }
    
    @Override
    public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            mIsAttached = false;
            source.getLifecycle().removeObserver(this);
        }
    }
    .......
}

SavedStateHandleController 它繼承自 LifecycleEventObserver 接口摆马,所以它是一個(gè)生命周期事件的觀察者,觀察生命周期的主要目的是當(dāng)宿主(Activity 或 Fragment)調(diào)用了 ON_DESTROYED 事件后鸿吆,對自己進(jìn)行一個(gè)移除囤采,以便進(jìn)行回收。

SavedStateHandleController 除了上面的特點(diǎn)外惩淳,還有下面這個(gè)主要的職責(zé):它是一個(gè)對 SavedStateHandle 對象進(jìn)行控制的管理類蕉毯。所有對 SavedStateHandle 的訪問都需要通過 SavedStateHandleController 來進(jìn)行。

它這里主要做了這幾件事情:

  1. 通過 SavedStateViewModelFactory 中的 mLifecycle 對象思犁,將自己綁定在當(dāng)前頁面的生命周期中代虾。并將 SavedStateHandle 中的回調(diào)方法 mSavedStateProvider 注冊到了 SavedStateRegistry 對象中(這個(gè)對象是做什么的,后面會講)抒倚,這樣做的結(jié)果是當(dāng)頁面回調(diào) onSaveInstanceState 時(shí)褐着,SavedStateRegistry 在保存數(shù)據(jù)的過程中,會回調(diào) SavedStateHandle 的 saveState() 方法來將 SavedStateHandle 中的數(shù)據(jù)進(jìn)行保存托呕。這個(gè)主要是在 attachToLifecycle() 方法中做的事情含蓉。
  2. 創(chuàng)建 SavedStateHandle 對象和自己。SavedStateHandleController 的創(chuàng)建是通過 SavedStateViewModelFactory 來創(chuàng)建的项郊,由于這里每調(diào)用一次 create() 函數(shù)就會創(chuàng)建一個(gè)新的 SavedStateHandleController 和 SavedStateHandle 對象馅扣。也就是說每一個(gè) SavedStateViewModelFactory 對象會對應(yīng)多個(gè) SavedStateHandleController 及 SavedStateHandle 對象。為什么有這種對應(yīng)關(guān)系呢着降?這里我覺得主要是因?yàn)?SavedStateHandleController 是一個(gè) LifecycleEventObserver 對象差油,當(dāng)頁面被銷毀后,該對象也會被回收任洞,對應(yīng)的 SavedStateHandle 也會被回收蓄喇。如果是 configuration 發(fā)生變化導(dǎo)致的頁面重啟的話,新的 SavedStateHandle 對象會將頁面的保存數(shù)據(jù)重新存儲到新的 SavedStateHandle 中交掏。 當(dāng)然妆偏,這里其實(shí)不會出現(xiàn)創(chuàng)建多個(gè) SavedStateHandleController 和 SavedStateHandle 的情況,主要是因?yàn)樵?get() 方法去獲取對應(yīng)的 ViewModel 時(shí)盅弛,如果還沒有創(chuàng)建才會去創(chuàng)建對應(yīng)的對象钱骂,如果已經(jīng)創(chuàng)建過了會直接去 mViewModelStore 緩存中獲取叔锐。

4. SavedStateHandle

public final class SavedStateHandle {
    final Map<String, Object> mRegular;
    private final Map<String, SavingStateLiveData<?>> mLiveDatas = new HashMap<>();

    private static final String VALUES = "values";
    private static final String KEYS = "keys";

    // 該回調(diào)用于當(dāng)頁面被非正常銷毀后,保存當(dāng)前數(shù)據(jù)使用的
    private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
        @SuppressWarnings("unchecked")
        @NonNull
        @Override
        public Bundle saveState() {
            Set<String> keySet = mRegular.keySet();
            ArrayList keys = new ArrayList(keySet.size());
            ArrayList value = new ArrayList(keys.size());
            for (String key : keySet) {
                keys.add(key);
                value.add(mRegular.get(key));
            }

            Bundle res = new Bundle();
            // "parcelable" arraylists - lol
            res.putParcelableArrayList("keys", keys);
            res.putParcelableArrayList("values", value);
            return res;
        }
    };
    
    static SavedStateHandle createHandle(@Nullable Bundle restoredState,
        @Nullable Bundle defaultState) {
    if (restoredState == null && defaultState == null) {
        return new SavedStateHandle();
    }

    // 保存默認(rèn)狀態(tài)
    Map<String, Object> state = new HashMap<>();
    if (defaultState != null) {
        for (String key : defaultState.keySet()) {
            state.put(key, defaultState.get(key));
        }
    }

    if (restoredState == null) {
        return new SavedStateHandle(state);
    }

    // 如果頁面非正常銷毀后见秽,保存了數(shù)據(jù)的話愉烙,會在再次創(chuàng)建該對象的時(shí)候,
    // 將之前頁面所保存的數(shù)據(jù)存儲到當(dāng)前 SavedStateHandle 對象中
    ArrayList keys = restoredState.getParcelableArrayList(KEYS);
    ArrayList values = restoredState.getParcelableArrayList(VALUES);
    if (keys == null || values == null || keys.size() != values.size()) {
        throw new IllegalStateException("Invalid bundle passed as restored state");
    }
    for (int i = 0; i < keys.size(); i++) {
        state.put((String) keys.get(i), values.get(i));
    }
    return new SavedStateHandle(state);
    
    ........
}

SavedStateHandle 該對象用于在 ViewModel 對象中保存頁面數(shù)據(jù)解取。前面我們講過步责,只有通過指定 SavedStateViewModelFactory 為創(chuàng)建 ViewModel 的工廠對象,且所實(shí)現(xiàn)的 ViewModel 中有一個(gè)構(gòu)造函數(shù)是接收一個(gè)參數(shù)且參數(shù)類型為 SavedStateHandle 的情況下肮蛹,才會使創(chuàng)建出來的 ViewModel 可以接收勺择,保存及使用頁面數(shù)據(jù)。

當(dāng)頁面被非正常銷毀后伦忠,SavedStateHandle 中的 mSavedStateProvider 監(jiān)聽方法會被調(diào)用省核,以保存當(dāng)前 SavedStateHandle 中的所有數(shù)據(jù),因?yàn)?SavedStateHandle 會隨著頁面的銷毀而被回收昆码。

SavedStateHandle 提供了 set(@NonNull String key, @Nullable T value) 方法來保存數(shù)據(jù)气忠。默認(rèn)都會以值為 Object 類型的方式存儲在 mRegular 參數(shù)中。

同時(shí)赋咽,還提供了兩種訪問數(shù)據(jù)的方式旧噪,都是通過 key 的方式來獲取值,不同的是脓匿,返回值的類型有所區(qū)別淘钟。一種是直接返回類型為 Object 類型的對象。另一種是返回 MutableLiveData 對象陪毡。分別對應(yīng)的存儲對象是 Map<String, Object> mRegularMap<String, SavingStateLiveData<?>> mLiveDatas米母。這里 mRegular 和 mLiveDatas 的關(guān)系又是怎樣的呢?

private <T> MutableLiveData<T> getLiveDataInternal(
        @NonNull String key,
        boolean hasInitialValue,
        @Nullable T initialValue) {
    MutableLiveData<T> liveData = (MutableLiveData<T>) mLiveDatas.get(key);
    // 第一次進(jìn)來這里的 liveData 為 null
    if (liveData != null) {
        return liveData;
    }
    SavingStateLiveData<T> mutableLd;
    // double hashing but null is valid value
    if (mRegular.containsKey(key)) {
        mutableLd = new SavingStateLiveData<>(this, key, (T) mRegular.get(key));
    } else if (hasInitialValue) {
        mutableLd = new SavingStateLiveData<>(this, key, initialValue);
    } else {
        // 如果 mRegular 中沒有對應(yīng)的值毡琉,而又沒有指令默認(rèn)值铁瞒,則直接創(chuàng)建一個(gè) // 值為 null 的 LiveData 對象
        mutableLd = new SavingStateLiveData<>(this, key);
    }
    // 將創(chuàng)建的 LiveData 對象緩存起來
    mLiveDatas.put(key, mutableLd);
    return mutableLd;
}

從其 get() 方法中可以看出,mRegular 是一個(gè)全量的數(shù)據(jù)表桅滋,所有的數(shù)據(jù)都會存儲到這里慧耍。當(dāng)調(diào)用獲取 LiveData 數(shù)據(jù)類型的數(shù)據(jù)時(shí),會先去 mLiveDatas 里直接獲取丐谋,如果不存在芍碧,就會去 mRegular 中獲取,獲取到了号俐,將其封裝成 LiveData 對象师枣,并將其緩存到 mLiveDatas 中,然后再返回這個(gè) LiveData 對象萧落。

可以看出践美,這個(gè) SavedStateHandle 對象是 ViewModel 組件提供的一種默認(rèn)保存及獲取頁面數(shù)據(jù)的方式。

5. SavedStateRegistryController 和 SavedStateRegistry

SavedStateRegistryController 其實(shí)什么也沒有做找岖,只是一個(gè)對 SavedStateRegistry 的代理類陨倡。實(shí)際的實(shí)現(xiàn)都是在 SavedStateRegistry 中做的,所以许布,我們直接分析 SavedStateRegistry 對象就可以了兴革。

SavedStateRegistry 這個(gè)對象是頁面真正保存數(shù)據(jù)的地方,每個(gè)頁面都綁定了一個(gè) SavedStateRegistry 對象蜜唾,當(dāng)頁面由于非正常銷毀而調(diào)用了 ON_DESTROYED 事件后杂曲,會調(diào)用 onSaveInstanceState(bundle) 回調(diào)方法來進(jìn)行頁面的數(shù)據(jù)保存工作,而真實(shí)的數(shù)據(jù)是保存在 bundle 對象中的袁余。在 onSaveInstanceState(bundle) 回調(diào)方法中擎勘,調(diào)用了 mSavedStateRegistryController.performSave(outState) 方法,實(shí)際上就是調(diào)用了 SavedStateRegistry 的 performSave(outState)颖榜。

@MainThread
void performSave(@NonNull Bundle outBundle) {
    Bundle components = new Bundle();
    if (mRestoredState != null) {
        components.putAll(mRestoredState);
    }
    // 通知各個(gè) SavedStateProvider 來保存各自的數(shù)據(jù)
    for (Iterator<Map.Entry<String, SavedStateProvider>> it =
            mComponents.iteratorWithAdditions(); it.hasNext(); ) {
        Map.Entry<String, SavedStateProvider> entry1 = it.next();
        components.putBundle(entry1.getKey(), entry1.getValue().saveState());
    }
    outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
}

這個(gè)方法的主要功能主要是將所有通過 registerSavedStateProvider(key,provider) 注冊到了 SavedStateRegistry 對象里棚饵,表示當(dāng)頁面由非正常銷毀時(shí),這些實(shí)際了 provider 監(jiān)聽的對象需要進(jìn)行數(shù)據(jù)保存掩完。而這里就是回調(diào)各個(gè)設(shè)置了監(jiān)聽對象噪漾,通過調(diào)用 saveState() 回調(diào)函數(shù),來將對象的數(shù)據(jù)保存到 Bundle 對象中且蓬。

而當(dāng)頁面的由于非正常銷毀之后重啟時(shí)欣硼,調(diào)用了 onCreate(@Nullable Bundle savedInstanceState) 回調(diào)函數(shù)后,會調(diào)用 mSavedStateRegistryController.performRestore(savedInstanceState) 方法對之前保存的數(shù)據(jù)進(jìn)行恢復(fù)恶阴。

    void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
        if (mRestored) {
            throw new IllegalStateException("SavedStateRegistry was already restored.");
        }
        if (savedState != null) {
            mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
        }
        ......
        mRestored = true;
    }

該方法主要是將保存在 Bundle 對象中的對應(yīng)的 Bundle 對象獲取出來诈胜,保存在當(dāng)前對象的 mRestoredState 中。那對應(yīng)的訂閱了當(dāng)前對象的 SavedStateProvider 如果恢復(fù)其數(shù)據(jù)呢存淫?

這里的 SavedStateProvider 主要是 SavedStateHandle 對象中實(shí)現(xiàn)了 SavedStateProvider 回調(diào)函數(shù)耘斩。我們前面說過,每個(gè) SavedStateViewModelFactory 正常情況下綁定一個(gè) SavedStateHandleController 對象桅咆。當(dāng)頁面重新加載的時(shí)候括授,會調(diào)用 SavedStateViewModelFactory 去創(chuàng)建對應(yīng)的 帶有一個(gè)參數(shù)為 SavedStateHandle 的 ViewModel 對象。在創(chuàng)建的過程中岩饼,會調(diào)用 SavedStateHandleController 的 `create()方法荚虚,在這個(gè)create()方法中會調(diào)用 SavedStateRegistry 對象的consumeRestoredStateForKey(key)`` 方法。

public Bundle consumeRestoredStateForKey(@NonNull String key) {
    if (!mRestored) {
        throw new IllegalStateException("You can consumeRestoredStateForKey "
                + "only after super.onCreate of corresponding component");
    }
    if (mRestoredState != null) {
        Bundle result = mRestoredState.getBundle(key);
        mRestoredState.remove(key);
        if (mRestoredState.isEmpty()) {
            mRestoredState = null;
        }
        return result;
    }
    return null;
}

原來其實(shí)訂閱了監(jiān)聽的對象都是通過該方法去獲取之前保存的數(shù)據(jù)籍茧,然后在 SavedStateHandle 重新創(chuàng)建的過程中版述,通過之前保存時(shí)用的 key 作為參數(shù)去調(diào)用 consumeRestoredStateForKey(key) 函數(shù)來獲取保存數(shù)據(jù)并恢復(fù)數(shù)據(jù)的。

static SavedStateHandle createHandle(@Nullable Bundle restoredState,
        @Nullable Bundle defaultState) {
    if (restoredState == null && defaultState == null) {
        return new SavedStateHandle();
    }

    Map<String, Object> state = new HashMap<>();
    if (defaultState != null) {
        for (String key : defaultState.keySet()) {
            state.put(key, defaultState.get(key));
        }
    }

    if (restoredState == null) {
        return new SavedStateHandle(state);
    }

    ArrayList keys = restoredState.getParcelableArrayList(KEYS);
    ArrayList values = restoredState.getParcelableArrayList(VALUES);
    if (keys == null || values == null || keys.size() != values.size()) {
        throw new IllegalStateException("Invalid bundle passed as restored state");
    }
    for (int i = 0; i < keys.size(); i++) {
        state.put((String) keys.get(i), values.get(i));
    }
    return new SavedStateHandle(state);
}

上面的方法就是 SavedStateHandle 對象中用來創(chuàng)建對象及恢復(fù)數(shù)據(jù)的方法寞冯。

6. AndroidViewModel

AndroidViewModel 也是組件提供的一個(gè)默認(rèn)的實(shí)現(xiàn)類渴析,但其實(shí)里面什么都沒有晚伙,只是持有了一個(gè) mApplication 對象。這個(gè) ViewModel 也是由默認(rèn)的 SavedStateViewModelFactory 工廠對象來創(chuàng)建的俭茧,其實(shí)功能和上面的實(shí)現(xiàn)是差不多的咆疗,只是比上面我們的 ViewModel 實(shí)現(xiàn)是直接實(shí)現(xiàn) ViewModel 對象的。

class SaveStateViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() {
}

而如果想要使用 AndroidViewModel 的話母债,需要上面的方法直接繼承 AndroidViewModel 對象午磁,而不是 ViewModel。

class SaveStateAndroidViewModel(
    application: Application,
    val savedStateHandle: SavedStateHandle
) : AndroidViewModel(application)

其實(shí)就比上面多了一個(gè) application毡们,其它都一樣迅皇,就不多說了。

講到這里衙熔,我想先對 SaveStateXXXX 相關(guān)的交互做一個(gè)總結(jié)吧登颓。這里一系列的實(shí)現(xiàn),其實(shí)就是將 ViewModel 中的數(shù)據(jù)保存到由頁面回調(diào) onSaveInstanceState(@NonNull Bundle outState)onCreate(@Nullable Bundle savedInstanceState) 中的 Bundle 對象中的一系列交互青责。只要是通過 SavedStateRegistry 對象中的 registerSavedStateProvider() 方法注冊了 SavedStateProvider 回調(diào)的對象都可以將數(shù)據(jù)存儲到系統(tǒng)提供的 bundle 對象中(關(guān)于這里的數(shù)據(jù)存儲的系統(tǒng)實(shí)現(xiàn)挺据,在這里不作展開)。

而這里主要是通過一系列的交互實(shí)現(xiàn)了一個(gè)帶 SavedStateHandle 參數(shù)的 ViewModel 對象脖隶。來將頁面和 ViewModel 中的數(shù)據(jù)都存儲在 bundle 對象中扁耐。

image

上圖是一個(gè) SaveStateViewModel 的創(chuàng)建過程。圖上面已經(jīng)比較清楚了产阱,我這里就不在贅述了婉称。下面是 SavedStateHandle 保存數(shù)據(jù)的過程。

image

下面是 SavedStateHandle 恢復(fù)數(shù)據(jù)的過程构蹬。

image

最后一點(diǎn)就是 SaveStateViewModel 構(gòu)造函數(shù)中 SavedStateHandle 對象哪里來的呢王暗?這個(gè)對象其實(shí)是 SavedStateViewModelFactory 在創(chuàng)建 SaveStateViewModel 對象之前通過 SavedStateHandleController 對象創(chuàng)建建了 SavedStateHandle 對象并傳遞給了對應(yīng)的 SavedStateViewModel 對象。

好了庄敛,到這里 ViewModel 在使用頁面非正常銷毀來保存數(shù)據(jù)機(jī)制的內(nèi)容就說完了俗壹。

7. ViewModel

ViewModel 是組件提供的一個(gè)抽象的 ViewModel 類,為方便使用者實(shí)現(xiàn)自定義的 ViewModel 對象藻烤。

<T> T setTagIfAbsent(String key, T newValue) {
    T previous;
    synchronized (mBagOfTags) {
        previous = (T) mBagOfTags.get(key);
        if (previous == null) {
            mBagOfTags.put(key, newValue);
        }
    }
    T result = previous == null ? newValue : previous;
    if (mCleared) {
        // It is possible that we'll call close() multiple times on the same object, but
        // Closeable interface requires close method to be idempotent:
        // "if the stream is already closed then invoking this method has no effect." (c)
        closeWithRuntimeException(result);
    }
    return result;
}

這個(gè)方法主要是用來保存與當(dāng)前 ViewModel 所綁定的 SavedStateHandle 對象的代理類 SavedStateHandleController绷雏。在 SavedStateViewModelFactory 的 create() 方法創(chuàng)建 ViewModel 的時(shí)候,調(diào)用的該方法怖亭,將對應(yīng)的 SavedStateHandleController 對象緩存了起來涎显。

通過上面的方法可以看出,當(dāng) key 對應(yīng)的對象已經(jīng)有值的時(shí)候兴猩,再次調(diào)用該方法不會再更新緩存的舊的值期吓。同時(shí)將舊的值返回。

<T> T getTag(String key) {
    if (mBagOfTags == null) {
        return null;
    }
    synchronized (mBagOfTags) {
        return (T) mBagOfTags.get(key);
    }
}

該方法就是通過 key 獲取對應(yīng)緩存的 SavedStateHandleController 的值倾芝。

@MainThread
final void clear() {
    mCleared = true;
    if (mBagOfTags != null) {
        synchronized (mBagOfTags) {
            for (Object value : mBagOfTags.values()) {
                // see comment for the similar call in setTagIfAbsent
                closeWithRuntimeException(value);
            }
        }
    }
    onCleared();
}

該方法用于清除所有的緩存數(shù)據(jù)讨勤,并通過 onCleared() 方法回調(diào)給 ViewModel 的實(shí)現(xiàn)類箭跳。而這個(gè)方法在什么時(shí)候被調(diào)用呢?它是在 ViewModelStore 中的 clear 方法被調(diào)用的悬襟。那這個(gè) ViewModelStore 的 clear() 方法又是在哪里被調(diào)用的呢衅码?

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();
            }
        }
    }
});

原來是在對應(yīng)頁面執(zhí)行了 ON_DESTROY 事件而且在不是屏幕旋轉(zhuǎn)發(fā)生配置改變的情況下,就會調(diào)用 clear() 方法脊岳,用于清除所有緩存在當(dāng)前頁面中的 ViewModel 及 ViewModel 所緩存的 SaveStateHandle 對象。

這也就是為什么數(shù)據(jù)緩存在 ViewModel 時(shí)垛玻,當(dāng)頁面由于旋轉(zhuǎn)屏幕而導(dǎo)致的非正常銷毀情況下割捅,數(shù)據(jù)還存在的原因。那新創(chuàng)建的 activity 又是如果再次綁定對應(yīng)的 ViewModel 對象的呢帚桩?

static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}

其實(shí) Activity 會將創(chuàng)建的對應(yīng)的 viewModelStore 使用 NonConfigurationInstances 對象緩存起來亿驾,當(dāng) Activity 在執(zhí)行 ON_DESTROYED 事件時(shí),當(dāng)不是因?yàn)樾D(zhuǎn)屏幕導(dǎo)致的銷毀的話账嚎,就會清除該對應(yīng)中的緩存莫瞬;相反,如果是由于旋轉(zhuǎn)屏幕而導(dǎo)致頁面重啟的話郭蕉,就不會清除該緩存疼邀。當(dāng) Activity 重新創(chuàng)建后,通過 getViewModelStore() 去獲取 ViewModelStore 對象時(shí)召锈,就會直接返回 NonConfigurationInstances 中的緩存旁振,也就完成了將銷毀的 Activity 的 ViewModelStore 綁定到了新創(chuàng)建的 Activity 中。

8. ViewModelStore

ViewModelStore 對象就是用于緩存對應(yīng)頁面所創(chuàng)建的 ViewModel 對象涨岁。其生命周期與頁面(Activity拐袜,F(xiàn)ragment)的生命周期是一樣的。

final void put(String key, ViewModel viewModel) {
    ViewModel oldViewModel = mMap.put(key, viewModel);
    if (oldViewModel != null) {
        oldViewModel.onCleared();
    }
}

當(dāng)通過工廠創(chuàng)建了 ViewModel 對象之后梢薪,會調(diào)用該 put() 方法將其緩存起來蹬铺。從上面的代碼可以看出,如果 key 相同的情況下秉撇,新的 ViewModel 對象會更新舊的值甜攀,并回調(diào)舊值的 onCleared() 方法來通知舊的對象,已經(jīng)被回收了畜疾。

public final void clear() {
    for (ViewModel vm : mMap.values()) {
        vm.clear();
    }
    mMap.clear();
}

這個(gè) clear() 方法會在頁面正常關(guān)閉后被調(diào)用赴邻,用來清除所有 ViewModel 對應(yīng)的 SavedStateHandle 緩存和 ViewModelStore 中的 ViewModel 緩存。

到這里啡捶,所有和 ViewModel 相關(guān)的主要類的介紹就已經(jīng)講完了姥敛。后面我們來分析一下比較重要的流程。

3. 重要流程梳理

3.1. 使用自定義 Factory 創(chuàng)建 ViewModel 的執(zhí)行流程

class ViewModelFactory(private val repository:MuseumDataSource):ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MuseumViewModel(repository) as T
    }
}

ViewModelProvider(this,Injection.provideViewModelFactory()).get(MuseumViewModel::class.java)

上面是一個(gè)自定義 Factory 的實(shí)現(xiàn)瞎暑。我們來分析一下通過自定義工廠來獲取 ViewModel 的整個(gè)執(zhí)行流程彤敛。

  1. 通過 ViewModelProvider 對象与帆,傳入當(dāng)前 Activity 對象主要是獲取其對應(yīng)的 ViewModelStore 對象,另外一個(gè)參數(shù)墨榄,就是我們創(chuàng)建的自定義的 Factory 工廠類玄糟,緩存在 ViewModelProvider 對象中。
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}
  1. 調(diào)用 get(clz) 方法獲取對應(yīng)的 ViewModel 對象袄秩。這里由于沒有指定對應(yīng)的 key阵翎,所以會使用 DEFAULT_KEY + cannonicalName 的形式來作為對應(yīng)的 key 值。
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);
}

接下來調(diào)用到了真正的獲取 ViewModel 的方法之剧。

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);

    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            // 這里的最終操作實(shí)際上是檢測了一下當(dāng)前 SavedStateViewModel 所綁定的 SavedStateHandle 對象是否未綁定當(dāng)前頁面的生命周期郭卫。如果沒有,就重新綁定一下背稼。
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    if (mFactory instanceof KeyedFactory) {
        // 如果使用的是系統(tǒng)提供的默認(rèn)的 SavedStateViewModelFactory 工廠的話贰军,會調(diào)用到這里
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
    } else {
        // 自定義工廠所執(zhí)行的地方
        viewModel = (mFactory).create(modelClass);
    }
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

上面的方法的主要執(zhí)行過程是:先從緩存中獲取對應(yīng)的 ViewModel 對象,如果已經(jīng)有緩存蟹肘,就直接返回词疼。而如果沒有緩存就會調(diào)用下面的對應(yīng)工廠來創(chuàng)建。而我們指定的是對應(yīng)的自定義工廠帘腹,所以會直接執(zhí)行 (mFactory).create(modelClass) 方法贰盗,最后將創(chuàng)建的 ViewModel 緩存起來。

viewModel = (mFactory).create(modelClass);

這里的 mfactory 就是我們上面?zhèn)鬟f的自定義工廠對象竹椒,所以這里直接會調(diào)用 override fun <T : ViewModel?> create(modelClass: Class<T>): T 方法童太。然后,直接創(chuàng)建了自定義的 MuseumViewModel(repository) as T 對象胸完,并將其返回书释。

到這里,使用自定義 Factory 創(chuàng)建 ViewModel 的執(zhí)行流程就說完了赊窥。整個(gè)流程比較的簡單爆惧,沒有太多的東西可以講的。

3.2. 使用系統(tǒng)默認(rèn)的工廠來創(chuàng)建 ViewModel 對象

這里分兩種情況锨能,一種情況是 ViewModel 中沒有一個(gè)構(gòu)造函數(shù)的簽名滿足下面這兩種情況:

private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class[]{Application.class,
        SavedStateHandle.class};
private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class[]{SavedStateHandle.class};

這樣的情況下扯再,創(chuàng)建該 ViewModel 的工廠使用的是 NewInstanceFactory 對象,而這個(gè)對象的 create() 方法非常的簡單址遇。

public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
    //noinspection TryWithIdenticalCatches
    try {
        return modelClass.newInstance();
    } catch (InstantiationException e) {
        throw new RuntimeException("Cannot create an instance of " + modelClass, e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException("Cannot create an instance of " + modelClass, e);
    }
}

直接通過反射的方式調(diào)用了 ViewModel 中無參數(shù)的構(gòu)造函數(shù)來創(chuàng)建對應(yīng)的 ViewModel 對象熄阻。這里需要注意的是,如果對應(yīng)的 ViewModel 中沒有無參的構(gòu)造函數(shù)倔约,就會rbqa報(bào)錯(cuò)秃殉。

另一種情況是 ViewModel 中滿足上面兩種方法簽名中的任意一個(gè)。這種情況下,就會使用 SavedStateViewModelFactory 工廠來創(chuàng)建 ViewModel 對象钾军。創(chuàng)建出來的 ViewModel 對象除了具有正常 ViewModel 對象所具備的功能外鳄袍,還可以通過 SavedStateHandle 對象來保存當(dāng)前 ViewModel 中的數(shù)據(jù)。這里主要使用的是頁面回調(diào)函數(shù) onSaveInstanceState(@NonNull Bundle outState) 中的 outState 的這個(gè) bundle 對象來保存數(shù)據(jù)吏恭。

這個(gè)方法被調(diào)用的情況主要有以下幾種情況:

1拗小、當(dāng)用戶按下HOME鍵時(shí)。
2樱哼、從最近應(yīng)用中選擇運(yùn)行其他的程序時(shí)哀九。
3、按下電源按鍵(關(guān)閉屏幕顯示)時(shí)搅幅。
4勾栗、從當(dāng)前activity啟動一個(gè)新的activity時(shí)。
5盏筐、屏幕方向切換時(shí)(無論豎屏切橫屏還是橫屏切豎屏都會調(diào)用)。

在前4種情況下砸讳,當(dāng)前activity的生命周期為:
onPause -> onSaveInstanceState -> onStop琢融。

這幾種情況都是當(dāng)出現(xiàn)這些情況后,如果出現(xiàn) Activity 被系統(tǒng)回收的情況簿寂,當(dāng)再次創(chuàng)建該 Activity 對象時(shí)漾抬,就會在 onCreate(@Nullable Bundle savedInstanceState) 回調(diào)函數(shù)中收到之前保存到 outBundle 對象中的 bundle 對象。然后最終通過 SavedStateHandle 進(jìn)行數(shù)據(jù)的恢復(fù)工作常遂。

第二種方法的好處

默認(rèn)情況下纳令,ViewModel 只有在 Activity 是因?yàn)樾D(zhuǎn)屏幕的情況被系統(tǒng)重啟的情況下,才可以復(fù)用之前的 ViewModel克胳,從而達(dá)到數(shù)據(jù)保存的效果平绩。而如果是我們上面所說的其它四種情況導(dǎo)致的 Activity 被銷毀后又被重新創(chuàng)建的情況,對應(yīng)的 ViewModel 也就會回收漠另,這樣保存在 ViewModel 的數(shù)據(jù)也會被回收捏雌。而使用第二種情況,當(dāng)出現(xiàn)上面幾種情況的時(shí)候笆搓,對應(yīng)的數(shù)據(jù)還是可以得到緩存性湿,并在重建的時(shí)候進(jìn)行數(shù)據(jù)恢復(fù)。

當(dāng)然满败,這里需要使第二種方法起到保存 ViewModel 中數(shù)據(jù)的作用肤频,還必須自己手動的將 ViewModel 中的數(shù)據(jù)對象存儲到對應(yīng)的 SavedStateHandle 對象中。

4. 結(jié)語

ViewModel 的主流程的分析相對是比較容易的算墨。讓我一開始覺得有點(diǎn)困惑的是 SavedStateViewModel 的實(shí)現(xiàn)宵荒,這一塊的知識點(diǎn),一開始想來到為什么要這么設(shè)計(jì),所以骇扇,看著比較的不知所措摔竿。但當(dāng)你多看幾遍,并通過寫具體的代碼來實(shí)現(xiàn)的時(shí)候少孝,甚至通過對代碼調(diào)試之后继低,你就會明白設(shè)計(jì)者設(shè)計(jì)的用心。在分析源碼的時(shí)候稍走,不要想著一上來就把所有的東西搞懂袁翁。而是需要保持耐心,一遍一遍的多看婿脸,多試粱胜,多畫。只有這樣狐树,才有可能弄懂作者設(shè)計(jì)的用心焙压。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市抑钟,隨后出現(xiàn)的幾起案子涯曲,更是在濱河造成了極大的恐慌,老刑警劉巖在塔,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幻件,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛔溃,警方通過查閱死者的電腦和手機(jī)绰沥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來贺待,“玉大人徽曲,你說我怎么就攤上這事『莩郑” “怎么了疟位?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喘垂。 經(jīng)常有香客問我甜刻,道長,這世上最難降的妖魔是什么正勒? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任得院,我火速辦了婚禮,結(jié)果婚禮上章贞,老公的妹妹穿的比我還像新娘祥绞。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布蜕径。 她就那樣靜靜地躺著两踏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪兜喻。 梳的紋絲不亂的頭發(fā)上梦染,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機(jī)與錄音朴皆,去河邊找鬼帕识。 笑死,一個(gè)胖子當(dāng)著我的面吹牛遂铡,可吹牛的內(nèi)容都是我干的肮疗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扒接,長吁一口氣:“原來是場噩夢啊……” “哼伪货!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起钾怔,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤超歌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蒂教,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脆荷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年凝垛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜓谋。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡梦皮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出桃焕,到底是詐尸還是另有隱情剑肯,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布观堂,位于F島的核電站让网,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏师痕。R本人自食惡果不足惜溃睹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胰坟。 院中可真熱鬧因篇,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至商佑,卻和暖如春锯茄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背莉御。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工撇吞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人礁叔。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓牍颈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親琅关。 傳聞我的和親對象是個(gè)殘疾皇子煮岁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

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