Android ViewModel炒瘸,再學(xué)不會(huì)你砍我

之前工作用了很久MVP架構(gòu)了葱椭,雖然很好的解決了M層與V層的耦合關(guān)系吱涉,但巨多的接口莲组,難以復(fù)用罗标、難以單測(cè)的問(wèn)題一直縈繞心頭丈挟,久久不能平復(fù)~~~显沈,于是我將目光轉(zhuǎn)向了MVVM软瞎。

MVVM與MVP相比最大的區(qū)別就是用ViewModel(后文簡(jiǎn)稱VM)代替了原來(lái)的P層,這里的VM就是ViewModel拉讯。一句話概括它的特點(diǎn)---對(duì)數(shù)據(jù)狀態(tài)的持有和維護(hù)涤浇。換言之,它將原來(lái)P層關(guān)于數(shù)據(jù)的邏輯運(yùn)算與處理統(tǒng)一放到了VM中魔慷,而剩余的V層的操作建議使用Databinding只锭,從而形成最為簡(jiǎn)潔高效的MVVM架構(gòu)。說(shuō)到這呢院尔,推薦一篇舊文DataBinding蜻展,再學(xué)不會(huì)你砍我(系兄弟就砍偶系列?)。

回到VM的特點(diǎn)---對(duì)數(shù)據(jù)狀態(tài)的持有和維護(hù)邀摆。為什么需要做這些呢纵顾?事實(shí)上就是為了解決下面兩個(gè)開(kāi)發(fā)中常見(jiàn)的問(wèn)題。

  • Activity配置更改重建時(shí)(比如屏幕旋轉(zhuǎn))保留數(shù)據(jù)
  • UI組件(Activity與Fragment栋盹、Fragment與Fragment)間實(shí)現(xiàn)數(shù)據(jù)共享施逾。

對(duì)于第一條不用VM的情況下只能通過(guò)onSaveInstanceState保存數(shù)據(jù),當(dāng)activity重建后再通過(guò)onCreateonRestoreInstanceState方法的bundle中取出例获,但如果數(shù)據(jù)量較大汉额,數(shù)據(jù)的序列化和反序列化將產(chǎn)生一定的性能開(kāi)銷。

對(duì)于第二條如果不用VM榨汤,各個(gè)UI組件都要持有共享數(shù)據(jù)的引用闷愤,這會(huì)帶來(lái)兩個(gè)麻煩,第一件余,如果新增了共享數(shù)據(jù),各個(gè)UI組件需要再次聲明并初始化新增的共享數(shù)據(jù)遭居;第二啼器,某個(gè)UI組件對(duì)共享數(shù)據(jù)修改,無(wú)法直接通知其他UI組件俱萍,需手動(dòng)實(shí)現(xiàn)觀察者模式端壳。而VM結(jié)合LiveData就可以很輕松的實(shí)現(xiàn)這一點(diǎn)。

LiveData作為數(shù)據(jù)變化的驅(qū)動(dòng)器枪蘑,VM借助它可以寫(xiě)出十分簡(jiǎn)潔的MVVM代碼损谦。

接下來(lái)我們來(lái)看一下VM到底是如何實(shí)現(xiàn)上述需求的岖免,而事實(shí)上核心可以轉(zhuǎn)化為下面兩個(gè)問(wèn)題。

問(wèn)個(gè)正事.png

問(wèn)題

  1. VM是如何解決Activity與Fragment照捡、Fragment之間數(shù)據(jù)共享的問(wèn)題颅湘?
  2. VM是如何在Activity發(fā)生旋轉(zhuǎn)時(shí)保留數(shù)據(jù)的?不是也走onDestroy了嗎栗精?

ViewModel是什么闯参?

回答上面問(wèn)題之前我們要先了解一下VM到底是個(gè)啥。

public abstract class ViewModel {
    protected void onCleared() {
    }
}

就是個(gè)抽象類甚至連抽象方法都沒(méi)有悲立,簡(jiǎn)單的令人發(fā)指鹿寨。onCleared方法提供了釋放VM中資源的一個(gè)機(jī)會(huì),在Activity/Fragment的onDestroy生命周期中被調(diào)用薪夕。類庫(kù)內(nèi)部提供了一個(gè)實(shí)現(xiàn)類AndroidViewModel脚草。

public class AndroidViewModel extends ViewModel {
    private Application mApplication;

    public AndroidViewModel(@NonNull Application application) {
        mApplication = application;
    }

    public <T extends Application> T getApplication() {
        return (T) mApplication;
    }
}

AndroidViewModel內(nèi)持有Application的引用,所以通吃祝可以做一些全生命周期的工作馏慨。為什么不能持有一個(gè)Activity呢?這與ViewModel的生命周期有關(guān)嚼贡,我們稍后解釋熏纯。

創(chuàng)建ViewModel

接下來(lái)看看VM的創(chuàng)建,通常我們是這樣創(chuàng)建一個(gè)VM的粤策。

val viewModel = ViewModelProviders.of(this).get(AndroidViewModel::class.java)

這里的this可以是FragmentActivity或Fragment樟澜,他們都是support-v4包中控件,為的是向下兼容叮盘。
我們以FragmentActivity為例看看of方法做了什么秩贰。

### 1.1 ViewModelProviders
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    return of(activity, null);
}

public static ViewModelProvider of(@NonNull FragmentActivity activity,
        @Nullable Factory factory) {
    Application application = checkApplication(activity);
    if (factory == null) {
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    //這里用的工廠模式,vm的創(chuàng)建交由工廠完成柔吼,默認(rèn)使用AndroidViewModelFactory
    return new ViewModelProvider(ViewModelStores.of(activity), factory);
}

這兩個(gè)方法的返回值都是ViewModelProvider毒费,ViewModelProviders是操作ViewModelProvider的工具類,內(nèi)部都是獲取ViewModelProvider的靜態(tài)方法愈魏,而真正的VM的業(yè)務(wù)在ViewModelProvider中觅玻。

同理ViewModelStores和ViewModelStore的關(guān)系亦是如此。既然要保留VM的數(shù)據(jù)培漏,必然要有個(gè)存儲(chǔ)單元溪厘。ViewModelStore就是這個(gè)存儲(chǔ)單元,因?yàn)橐粋€(gè)Activity中可能有多個(gè)VM牌柄,所以需要一個(gè)Map來(lái)維護(hù)關(guān)系表畸悬,key為VM的名字,value為VM對(duì)象珊佣,簡(jiǎn)單的令人發(fā)指蹋宦。

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

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

ViewModelStores僅負(fù)責(zé)提供工具方法創(chuàng)建ViewModelStore披粟。

### 1.2
public class ViewModelStores {
    private ViewModelStores() {
    }

    public static ViewModelStore of(@NonNull FragmentActivity activity) {
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        return holderFragmentFor(activity).getViewModelStore();
    }
    ...
}

ViewModelStoreOwner又是什么鬼?它是抽象了一個(gè)獲取ViewModelStore的接口冷冗。常見(jiàn)的實(shí)現(xiàn)類有Fragment/FragmentActivity守屉,這也不難理解,因?yàn)橐朐谂渲酶淖儠r(shí)保留數(shù)據(jù)贾惦,首先得要將數(shù)據(jù)存儲(chǔ)起來(lái)胸梆。

public interface ViewModelStoreOwner {
    ViewModelStore getViewModelStore();
}

感覺(jué)這時(shí)需要一張類圖了,不然你是不是想砍死我须板?

format.jpg

事實(shí)上目前提到的這幾個(gè)類已經(jīng)幾乎涵蓋了viewmodel庫(kù)中所有的類碰镜。

我們回到1.1中創(chuàng)建ViewModelProvider的代碼。

return new ViewModelProvider(ViewModelStores.of(activity), factory);

我們將activity中的VM存儲(chǔ)單元和VM的創(chuàng)建工廠(AndroidViewModelFactory)傳入得到一個(gè)ViewModelProvider對(duì)象习瑰,最終通過(guò)其get方法得到VM绪颖。

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

以Default_Key作為前綴加上VM的完整類名為key,獲取VM對(duì)象甜奄。

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

    //先看ViewModelStore中是否存在柠横,如果存了就直接返回
    if (modelClass.isInstance(viewModel)) {
        return (T) viewModel;
    }
    ...
    //如果不存在,創(chuàng)建一個(gè)新的VM并存入ViewModelStore
    viewModel = mFactory.create(modelClass);
    mViewModelStore.put(key, viewModel);
    return (T) viewModel;
}

默認(rèn)情況下mFactory為AndroidViewModelFactory课兄,來(lái)看下它是如何創(chuàng)建VM的牍氛。

public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
    ...
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
            try {
                //通過(guò)反射創(chuàng)建AndroidViewModel對(duì)象
                return modelClass.getConstructor(Application.class).newInstance(mApplication);
            } catch (NoSuchMethodException e) {
                ...
            } 
        }
        return super.create(modelClass);
    }
}

至此VM的創(chuàng)建我們就講完了,可以總結(jié)一下:

  1. ViewModelStore是存儲(chǔ)VM的數(shù)據(jù)單元烟阐,存儲(chǔ)結(jié)構(gòu)為Map搬俊,F(xiàn)ragment/FragmentActivity持有其引用。
  2. ViewModelProvider通過(guò)get方法創(chuàng)建一個(gè)VM蜒茄,創(chuàng)建之前會(huì)先檢查ViewModelStore中是否存在唉擂,若不存在則通過(guò)反射創(chuàng)建一個(gè)VM。

UI組件間數(shù)據(jù)共享

講到這我們回過(guò)頭來(lái)看看開(kāi)篇提的第一個(gè)問(wèn)題:Activity與Fragment檀葛,F(xiàn)ragment之間是如何共享數(shù)據(jù)的玩祟。
數(shù)據(jù)要實(shí)現(xiàn)共享最簡(jiǎn)單的方式就是大家都讀取一份數(shù)據(jù)源。
我們來(lái)看看數(shù)據(jù)源ViewModelStore具體是在哪里創(chuàng)建的屿聋。

上面講的代碼片段1.2可知空扎,有兩條路徑創(chuàng)建。

public static ViewModelStore of(@NonNull FragmentActivity activity) {
    if (activity instanceof ViewModelStoreOwner) { ①
        return ((ViewModelStoreOwner) activity).getViewModelStore();
    }
    return holderFragmentFor(activity).getViewModelStore();②
}

①如果FragmentActivity是ViewModelStoreOwner類型通過(guò)activity的getViewModelStore方法創(chuàng)建润讥。

②否則通過(guò)一個(gè)HolderFragment來(lái)創(chuàng)建转锈。

先來(lái)看①

### FragmentActivity
private ViewModelStore mViewModelStore;
public ViewModelStore getViewModelStore() {
    ...
    if (mViewModelStore == null) {
        mViewModelStore = new ViewModelStore();
    }
    return mViewModelStore;
}

簡(jiǎn)單的令人發(fā)ck,既然是成員變量那每次調(diào)用必定返回同一個(gè)VM象对,只要保證調(diào)用ViewModelProviders.of(activity).get(AndroidViewModel::class.java)傳遞的activity是同一個(gè)對(duì)象。

再來(lái)看②宴抚,整體思路是添加一個(gè)不可見(jiàn)的HolderFragment到當(dāng)前Activity中勒魔,再將數(shù)據(jù)源記錄在這個(gè)fragment中甫煞。

### HolderFragment extends Fragment implements ViewModelStoreOwner
private ViewModelStore mViewModelStore = new ViewModelStore();

public static HolderFragment holderFragmentFor(FragmentActivity activity) {
    return sHolderFragmentManager.holderFragmentFor(activity);
}

HolderFragment holderFragmentFor(FragmentActivity activity) {
    FragmentManager fm = activity.getSupportFragmentManager();
    //先查一下當(dāng)前有沒(méi)有這個(gè)HolderFragment
    HolderFragment holder = findHolderFragment(fm);
    if (holder != null) {
        return holder;
    }
    ...
    //沒(méi)有就創(chuàng)建一個(gè)
    holder = createHolderFragment(fm);
    ...
    return holder;
}

private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
    //創(chuàng)建一個(gè)HolderFragment、打上tag冠绢,再添加到當(dāng)前界面抚吠。
    HolderFragment holder = new HolderFragment();
    fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
    return holder;
}

之所以不可見(jiàn),是因?yàn)檫@個(gè)HolderFragment并未復(fù)寫(xiě)onCreateView弟胀。這么做的原因是早期的版本想利用Fragment的setRetainInstance()API接口楷力,來(lái)實(shí)現(xiàn)當(dāng)Activity因配置發(fā)生改變時(shí)保留這個(gè)不可見(jiàn)的Fragment,生命周期只走onDetach和onAttach孵户。既然沒(méi)有被重建萧朝,那么它持有的數(shù)據(jù)自然就會(huì)被保留,其他主動(dòng)退出的情況走到onDestroy會(huì)清空數(shù)據(jù)夏哭。

### HolderFragment
public HolderFragment() {
    setRetainInstance(true);
}
//被銷毀時(shí)清除數(shù)據(jù)源
public void onDestroy() {
    super.onDestroy();
    mViewModelStore.clear();
}

那么在實(shí)際使用中會(huì)走哪條路徑呢检柬?我們反觀源碼FragmentActivity是實(shí)現(xiàn)了ViewModelStoreOwner接口的,那此處代碼不是肯定走①嗎竖配?②是不是走錯(cuò)片場(chǎng)了何址?此時(shí)我感覺(jué)我的智商受到了侮辱。

智商不足.jpeg

原來(lái)在appcompat-v7版本在27.1.0之前FragmentActivity并沒(méi)有實(shí)現(xiàn)ViewModelStoreOwner接口进胯,也就是統(tǒng)一用HolderFragment實(shí)現(xiàn)用爪。google大大可能是覺(jué)得這個(gè)HolderFragment有點(diǎn)太騷操作了就讓后續(xù)版本的FragmentActivity直接支持了VM存儲(chǔ)。因?yàn)樘砑拥腍olderFragment也是有維護(hù)成本的胁镐,且上層可以通過(guò)FragmentManager獲取到它偎血,然后對(duì)它進(jìn)行其他騷操作,想想都刺激希停。烁巫。。

深井冰.jpg

上面我們分析了創(chuàng)建VM時(shí)傳入FragmentActivity的情況宠能,那傳入Fragment的情況呢亚隙?實(shí)際上跟FragmentActivity幾乎一樣,在Fragment中也有一個(gè)mViewModelStore成員變量违崇,注意這里哦阿弃,非常關(guān)鍵。也就是說(shuō)如果我們通過(guò)下面的代碼創(chuàng)建的是兩個(gè)VM羞延,是不能共享數(shù)據(jù)的渣淳。

### MainActivity
override fun onCreate(savedInstanceState: Bundle?) {
    //傳遞activity
    val vm = ViewModelProviders.of(this).get(AndroidViewModel::class.java)
}

### TestFragment
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    //傳遞fragment
    val vm = ViewModelProviders.of(this).get(AndroidViewModel::class.java)
}

正確的寫(xiě)法應(yīng)該是二者在of方法中傳入相同的對(duì)象

### TestFragment.onCreate(savedInstanceState: Bundle?)
//通過(guò)getActivity方法取得Fragment所在的Activity
val vm = activity?.run {
    //run函數(shù) 這里的this指代activity
    ViewModelProviders.of(this)[AndroidViewModel::class.java]
}

Fragment之間同理,如果Fragment間同層級(jí)伴箩,可以統(tǒng)一通過(guò)Activity或共同的parentFragment(如果有)獲取VM入愧;如果有嵌套關(guān)系,可以使用parentFragment對(duì)象獲取VM。

Activity配置發(fā)生變化時(shí)數(shù)據(jù)保持

其實(shí)在上面的內(nèi)容中已經(jīng)講了HolderFragment是如何保留數(shù)據(jù)的棺蛛,就是利用Fragment的setRetainInstance()API接口完成的怔蚌。

google為了優(yōu)化這點(diǎn)在新版本里直接讓FragmentActivity支持了數(shù)據(jù)的保持,官方的配圖很好的闡釋了VM在Activity因配置變化銷毀重建時(shí)的生命周期旁赊。

viewmodel-lifecycle.png

下面我們來(lái)分析一下是如何做到的桦踊,先看onDestroy的銷毀邏輯。

### FragmentActivity
protected void onDestroy() {
    super.onDestroy();
    ...
    if (mViewModelStore != null && !mRetaining) {
        mViewModelStore.clear();
    }
    ...
}

mRetaining為true時(shí)將會(huì)保留VM數(shù)據(jù)终畅,那它何時(shí)為true呢籍胯?

### FragmentActivity
public final Object onRetainNonConfigurationInstance() {
    if (mStopped) {
        //方法內(nèi)部會(huì)將mRetaining設(shè)置為true
        doReallyStop(true);
    }
    ...
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    //保存VM數(shù)據(jù)
    nci.viewModelStore = mViewModelStore;
    nci.fragments = fragments;
    return nci;//數(shù)據(jù)返回會(huì)被記錄
}

onRetainNonConfigurationInstance方法被retainNonConfigurationInstances方法調(diào)用,而它會(huì)被ActivityThread中performDestroyActivity方法調(diào)用离福,它執(zhí)行在onDestroy生命周期之前杖狼。

### ActivityThread
performDestroyActivity(...boolean getNonConfigInstance,...) {
    ...
    if (getNonConfigInstance) {
        //如果配置發(fā)生改變記錄下來(lái)
        r.lastNonConfigurationInstances
                = r.activity.retainNonConfigurationInstances();
    }
}

這樣VM數(shù)據(jù)就被封裝到了NonConfigurationInstances一個(gè)對(duì)象中了。

那何時(shí)被還原呢术徊?答案是Activity的attach時(shí)本刽。

### Activity
final void attach(Context context, ... NonConfigurationInstances lastNonConfigurationInstances,...) {
    ...
    mLastNonConfigurationInstances = lastNonConfigurationInstances;
    ...
}

VM數(shù)據(jù)源mViewModelStore在onCreate時(shí)被重新賦值。

### FragmentActivity
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //還原數(shù)據(jù)
    NonConfigurationInstances nc =
            (NonConfigurationInstances) getLastNonConfigurationInstance();
    if (nc != null) {
        mViewModelStore = nc.viewModelStore;
    }
    ...
}

最后我們整理一下整體流程圖赠涮。

代碼流程.png

從上面的流程可以看出VM在Activity因配置變化導(dǎo)致重建時(shí)會(huì)被保留子寓,從生命周期的角度來(lái)說(shuō),ViewModel的生命周期可能會(huì)長(zhǎng)于Activity的生命周期笋除。

這說(shuō)明我們?cè)谑褂肰iewModel時(shí)一定要注意斜友,不能讓其引用Activity或View,否則可能導(dǎo)致內(nèi)存泄漏垃它。

好了鲜屏,整個(gè)ViewModel的分析就結(jié)束了,希望你在了解其工作原理的同時(shí)對(duì)MVVM模式也有一些新的認(rèn)識(shí)国拇。獨(dú)立的看ViewModel沒(méi)有什么實(shí)際意義洛史,更像是數(shù)據(jù)容器,結(jié)合LiveData使用更容易理解酱吝,后續(xù)章節(jié)會(huì)繼續(xù)分享LiveData的內(nèi)容也殖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市务热,隨后出現(xiàn)的幾起案子忆嗜,更是在濱河造成了極大的恐慌,老刑警劉巖崎岂,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捆毫,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡冲甘,警方通過(guò)查閱死者的電腦和手機(jī)绩卤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)途样,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人濒憋,你說(shuō)我怎么就攤上這事娘纷。” “怎么了跋炕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)律适。 經(jīng)常有香客問(wèn)我辐烂,道長(zhǎng),這世上最難降的妖魔是什么捂贿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任纠修,我火速辦了婚禮,結(jié)果婚禮上厂僧,老公的妹妹穿的比我還像新娘扣草。我一直安慰自己,他們只是感情好颜屠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布辰妙。 她就那樣靜靜地躺著,像睡著了一般甫窟。 火紅的嫁衣襯著肌膚如雪密浑。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天粗井,我揣著相機(jī)與錄音尔破,去河邊找鬼。 笑死浇衬,一個(gè)胖子當(dāng)著我的面吹牛懒构,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耘擂,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼胆剧,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了梳星?” 一聲冷哼從身側(cè)響起赞赖,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎冤灾,沒(méi)想到半個(gè)月后前域,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡韵吨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年匿垄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椿疗,死狀恐怖漏峰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情届榄,我是刑警寧澤浅乔,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站铝条,受9級(jí)特大地震影響靖苇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜班缰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一贤壁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧埠忘,春花似錦脾拆、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至旨怠,卻和暖如春包帚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背运吓。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工渴邦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拘哨。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓谋梭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親倦青。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓮床,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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

  • ViewModel是google官方的MVVM架構(gòu)組件,目前已經(jīng)集成到了最新的支持庫(kù)中了产镐,是MVVM架構(gòu)的核心組件...
    生椰拿鐵錘閱讀 15,891評(píng)論 2 89
  • 概述 ViewModel隘庄,從字面上理解的話,它肯定是跟視圖(View)以及數(shù)據(jù)(Model)相關(guān)的癣亚。正像它字面意思...
    陳曉松快點(diǎn)跑閱讀 3,186評(píng)論 0 11
  • 博文出處:Android Architecture Component之ViewModel解析丑掺,歡迎大家關(guān)注我的博...
    俞其榮閱讀 1,170評(píng)論 0 3
  • 早安 ――羅詩(shī)默 終究是蘇醒了 是啊 還沒(méi)向最愛(ài)的人說(shuō)節(jié)日快樂(lè) 17號(hào)還沒(méi)赴約 信件還沒(méi)發(fā)出 仙兒還沒(méi)安好 ...
    羅詩(shī)默閱讀 335評(píng)論 0 3
  • 云是自由的,歡快的述雾,放蕩不羈的街州,就像搖滾的吉他手沉浸在彈奏時(shí)像火苗般的頭發(fā)兼丰,所以它會(huì)有各種各樣的樣子,各種各樣色彩...
    正能量L7閱讀 118評(píng)論 0 0