像Activity,Fragment這類應用組件都有本身的生命週期而且是被Android的Framework所管理的。Framework可能會根據用戶的一些操做和設備的狀態對Activity或者Fragment進行銷燬和重構。做爲開發者,這些行爲咱們是沒法干預的。html
因此Activity或Fragment中的一些數據也會隨着銷燬而丟失,隨着重構而從新生成。好比你的Activity中有個用戶列表,當這個Activity重構的時候,新的Activity會從新獲取用戶列表。對於一些簡單的數據,Activity可使用onSaveInstanceState()
方法,並從onCreate的bundle中從新獲取。但這一方法途徑僅僅適合一些簡單的UI狀態,對於用戶列表這種龐大的數據並不適合。設計模式
還存在一個問題,Activity或者Fragment常常會作一些異步的耗時操做。隨之就須要Activity和Fragment管理這些異步操做,並在本身被destroyed的時候清理它們,從而保證內存溢出這類問題的發生。這樣的處理會隨着項目擴大而變得十分複雜,一不留神,你的App就Crash了。異步
Activity和Fragment自己須要處理不少用戶的輸入事件並和操做系統打交道,因此當它們還要花時間管理它們的數據資源時,class文件就會變得異常龐大,而後就會造就出所謂的god activities
和god fragments
。這些UI控制類僅僅靠一個class就能處理相關的全部事務。簡直跟上帝沒啥兩樣。但這些類若是要進行單元測試的話,那就尷尬了。async
因此就有了MVC
,MVP
這類設計模式,將視圖與數據分離。今天講到的ViewModel
類的功能也同樣,就是講數據從UI中分離出來。而且當Activity或Fragment重構的時候,ViewModel會自動保留以前的數據並給新的Activity或Fragment使用。對於上面提到的用戶列表的例子,ViewModel會爲咱們很好的管理這些數據。ide
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中就能這樣使用了:單元測試
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 }); } }
這是當MyActivity被重構時,得到到的model實例是與重構前同一個,當MyActivity被銷燬時,Framework會調用ViewModel的onCleared()
,咱們就能夠在此方法中作資源的清理。測試
由於ViewModel的生命週期是和Activity或Fragment分開的,因此在ViewModel中絕對不能引用任何View對象或者任何引用了Activity的Context的對象。若是ViewModel中須要Application的Context的話,能夠繼承
AndroidViewModel
。fetch
在Activity中包好多個Fragment而且須要相互通訊是很是常見的,這時就須要這些Fragment定義一些接口,而後讓Activity來進行協調。並且這些Fragment還須要處理其餘Fragment不可見或者尚未建立這些細節問題。this
上面這個動點能夠被ViewModel輕易解決,想象意向有這麼個Activity,它包含FragmentA和FragmentB,其中A是用戶列表,B是用戶的詳細數據,點擊列表上的某個用戶,在B中顯示相應的數據。spa
看看使用ViewModel怎麼處理這個問題:
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 onActivityCreated() { model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); itemSelector.setOnClickListener(item -> { model.select(item); }); } } public class DetailFragment extends LifecycleFragment { public void onActivityCreated() { SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); model.getSelected().observe(this, { item -> // update UI }); } }
這裏要注意的是兩個Fragment都使用了getActivity
做爲參數來得到ViewModel實例。這表示這兩個Fragment得到的ViewModel對象是同一個。
使用了ViewModel的好處以下:
ViewModel的生命週期跟着傳遞給ViewModelProvider
的LifeCycle
走,當生成了ViewModel的實例後,它會一直待在內存中,直到對應的LifeCycle完全結束。下面是ViewModel與Activity對應的生命週期圖: