理解Android Architecture Components系列之ViewModel(五)

ViewModel設(shè)計(jì)的目的就是存放和處理和UI相關(guān)的數(shù)據(jù),并且這些數(shù)據(jù)不受配置變化(Configuration Changes,例如:旋轉(zhuǎn)屏幕,組件被系統(tǒng)回收)的影響。

由于(Activity/Fragment)會(huì)被系統(tǒng)隨時(shí)銷毀或重新創(chuàng)建,因此,任何存放在這里的數(shù)據(jù)都可能會(huì)丟失。例如,Activity中有一個(gè)查詢得到的用戶列表,當(dāng)Activity被重新創(chuàng)建時(shí),新的Activity需要再次去獲取用戶數(shù)據(jù)。對(duì)于簡(jiǎn)單的數(shù)據(jù)可以使用 onSaveInstanceState()保存,在onCreate()中恢復(fù)。對(duì)于少量的用戶數(shù)據(jù),比如UI狀態(tài)是沒(méi)有問(wèn)題的。但是對(duì)于大量的數(shù)據(jù),比如用戶列表,這用做就會(huì)不合適(not suitable)。

另一個(gè)問(wèn)題是,UI組件會(huì)頻繁的調(diào)用異步回調(diào),這些回調(diào)可能會(huì)非常耗時(shí)。這就需要UI組件管理這些調(diào)用,并且在UI組件銷毀時(shí)清除這些調(diào)用。這會(huì)花費(fèi)很多的維護(hù)成本,而且當(dāng)UI由于configuration change重新創(chuàng)建時(shí),又需要重新調(diào)用,這明顯是一種資源浪費(fèi)(比如網(wǎng)絡(luò)請(qǐng)求)。

最后,還有一個(gè)問(wèn)題就是UI組件需要對(duì)用戶的操作作出響應(yīng),并且處理和操作系統(tǒng)的通信。這樣把代碼放在UI組件中會(huì)使這部分代碼變得臃腫,而且對(duì)測(cè)試也不太友好。

ViewModel就是用于解決上述問(wèn)題的。ViewModel用于為UI組件提供數(shù)據(jù),并且能夠在旋轉(zhuǎn)屏幕等Configuration Change發(fā)生時(shí),仍能保持里面的數(shù)據(jù)。當(dāng)UI組件恢復(fù)時(shí),可以立刻向UI提供數(shù)據(jù)。一起看下代碼:

public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<Users>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // do async operation to fetch users
    }
}

Activity訪問(wèn)User List數(shù)據(jù):

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

那么問(wèn)題來(lái)了,假如用戶按返回鍵,主動(dòng)銷毀了這個(gè)Activity呢?這時(shí)系統(tǒng)會(huì)調(diào)用ViewModel的onCleared()方法,清除ViewModel中的數(shù)據(jù)。

在Fragments間分享數(shù)據(jù)

有時(shí)候一個(gè)Activity中的兩個(gè)或多個(gè)Fragment需要分享數(shù)據(jù)或者相互通信,這樣就會(huì)帶來(lái)很多問(wèn)題,比如數(shù)據(jù)獲取,相互確定生命周期。

使用ViewModel可以很好的解決這個(gè)問(wèn)題。假設(shè)有這樣兩個(gè)Fragment,一個(gè)Fragment提供一個(gè)列表,另一個(gè)Fragment提供點(diǎn)擊每個(gè)item現(xiàn)實(shí)的詳細(xì)信息。

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class MasterFragment extends Fragment {
    private SharedViewModel model;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends LifecycleFragment {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
        model.getSelected().observe(this, { item ->
           // update UI
        });
    }
}

兩個(gè)Fragment都是通過(guò)getActivity()來(lái)獲取ViewModelProvider。這意味著兩個(gè)Activity都是獲取的屬于同一個(gè)Activity的同一個(gè)ShareViewModel實(shí)例。
這樣做優(yōu)點(diǎn)如下:

  • Activity不需要寫任何額外的代碼,也不需要關(guān)心Fragment之間的通信。
  • Fragment不需要處理除SharedViewModel以外其他的代碼。這兩個(gè)Fragment不需要知道對(duì)方是否存在。
  • Fragment的生命周期不會(huì)相互影響

ViewModel的生命周期

ViewModel只有在Activity finish或者Fragment detach之后才會(huì)銷毀。下面這張圖顯示了詳細(xì)的生命周期:


viewmodel-lifecycle.png

ViewModel和SavedInstanceState對(duì)比

ViewModel使得在configuration change(旋轉(zhuǎn)屏幕等)保存數(shù)據(jù)變的十分方便,但是這不能用于應(yīng)用被系統(tǒng)殺死時(shí)持久化數(shù)據(jù)。舉個(gè)簡(jiǎn)單的例子,有一個(gè)界面展示國(guó)家信息。不應(yīng)該把整個(gè)國(guó)家信息放到SavedInstanceState里,而是把國(guó)家對(duì)應(yīng)的id放到SavedInstanceState,等到界面恢復(fù)時(shí),再通過(guò)id去獲取詳細(xì)的信息。這些詳細(xì)的信息應(yīng)該被存放在數(shù)據(jù)庫(kù)中。說(shuō)到數(shù)據(jù)庫(kù),下篇文章將會(huì)介紹Android Architecture Components提供的Room來(lái)操作數(shù)據(jù)庫(kù)。

相關(guān)文章:
理解Android Architecture Components系列(一)
理解Android Architecture Components系列(二)
理解Android Architecture Components系列之Lifecycle(三)
理解Android Architecture Components系列之LiveData(四)
理解Android Architecture Components系列之ViewModel(五)
理解Android Architecture Components系列之Room(六)
理解Android Architecture Components系列之Paging Library(七)
理解Android Architecture Components系列之WorkManager(八)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容