ViewModel的作用是爲界面準備數據,數據的獲取操作(如網絡請求)或者一些數據處理可以在該類中編寫方法,減少在Activity的代碼。
ViewModel裏面的數據可以分爲以下三類。
- 普通數據,只是負責保存數據,無特別作用,可當做普通類來用
public class DataViewModel extends ViewModel { public String name; public int age; }
- 與LiveData結合使用。MutableLiveData的取/賦值方法分別爲getValue(),setValue(),如果不在主線程,用postValue()。關於LiveData可以看我的另外一篇文章Android LiveData的使用
public class DataViewModel extends ViewModel { private MutableLiveData<String> name; private MutableLiveData<Integer> age; public MutableLiveData<String> getName() { if (name == null) { name = new MutableLiveData<String>(); //獲取初始值的操作,否則默認爲""。 } return name; } public MutableLiveData<Integer> getAge() { if (age == null) { age = new MutableLiveData<Integer>(); //獲取初始值的操作,否則默認爲0。 } return age; } }
- 與DataBinding結合使用,ObservableField自帶get/set方法。DataBinding的使用可以看我另外一篇文章Android DataBinding的簡單使用
/** * 什麼時候用MutableLiveData?什麼時候用ObservableField? * 雙向綁定看起來很便利,不需關注值的變化去更新視圖。但實際業務大多數要對輸入的值進行校驗並做一些處理,不僅僅只是把值賦給實體對象。 * 個人感覺用MutableLiveData比較靈活,有些時候控件是動態添加進佈局裏的,這種時候很難用ObservableField進行賦值(也很難進行邏輯處理), * 而使用MutableLiveData,在onChanged方法裏面我想更新什麼就更新什麼(邏輯寫在activity中思路也比較清晰) * 結論: * 1、在不用處理數據(即用戶輸入什麼就是什麼,不涉及邏輯處理)/只用做數據顯示(並且頁面佈局都由XML寫,不涉及動態添加控件)的情況下,使用ObservableField比較方便 * 2、其餘情況用MutableLiveData比較靈活 */ public class DataViewModel extends ViewModel { public final ObservableField<String> name = new ObservableField<>(); public final ObservableField<Integer> age = new ObservableField<>(); }
這三種類型可以分開使用,也可以看需求混合搭配使用。官方提供了以下的創建方法來獲取ViewModel的實體對象(我發佈這篇文章時,中文官網展示的方法還是舊版的,以下的代碼已經是修改後的最新方法,舊版方法已拋棄。無法保證以後版本更新會不會有新的創建方法,如以後發現代碼報錯,可去官網看最新代碼)。
- 這種方法獲取的ViewModel,僅在Activity第一次創建的時候會進行創建,之後將會複用之前創建好的ViewModel,可用於頁面狀態保存。
public class MyActivity extends AppCompatActivity { // Create a ViewModel the first time the system calls an activity's onCreate() method. // Re-created activities receive the same MyViewModel instance created by the first activity. public void onCreate(Bundle savedInstanceState) { ViewModelProvider.Factory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()); DataViewModel dataViewModel = new ViewModelProvider(this, factory).get(DataViewModel.class); } }
- 這種方法獲取的ViewModel,每次都會進行重新創建(個人感覺跟直接用new DataViewModel()沒什麼不同,有不同觀點的歡迎指出)。
public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { ViewModelProvider.Factory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()); DataViewModel dataViewModel = factory.create(DataViewModel.class); } }
爲了統一管理ViewModel,我寫了下面這個工具類,所有ViewModel都可以通過這個類的方法來創建(也可以把這幾個方法放在application的類裏)。getPrivateViewModel()對應上面的方法1。getViewModel()對應上面的方法2,並存放在一個靜態map中,可實現在多個頁面公用同一個ViewModel的數據。
import android.app.Activity;
import android.app.Application;
import java.util.HashMap;
import java.util.Map;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
/**
* ViewModel工具類
*/
public class ViewModelUtils {
private static Map<Class, ViewModel> viewModelMap = new HashMap<>();
/**
* 獲取全局唯一的ViewModel
* 常用與跨頁面修改數據(並且需要刷新顯示),比如在某個頁面對該ViewModel裏的MutableLiveData進行了observe,
* 無論在哪裏修改ViewModel裏面的MutableLiveData的值,這個頁面都會收到通知(頁面在活躍狀態下馬上收到,非活躍狀態下將在變爲活躍狀態的那一刻收到),收到通知後調用onChanged()方法(一般是刷新視圖)
* @param application 本項目所設置使用的application實體
* @param viewModelClass ViewModel對應的類
* @param <T>
* @return
*/
public static <T extends ViewModel> T getViewModel(Application application, Class<T> viewModelClass){
if (viewModelMap.containsKey(viewModelClass)){
return (T) viewModelMap.get(viewModelClass);
}
T t = ViewModelProvider.AndroidViewModelFactory.getInstance(application).create(viewModelClass);
viewModelMap.put(viewModelClass, t);
return t;
}
public static <T extends ViewModel> T getViewModel(Fragment fragment, Class<T> viewModelClass){
return getViewModel(fragment.getActivity(),viewModelClass);
}
public static <T extends ViewModel> T getViewModel(Activity activity, Class<T> viewModelClass){
return getViewModel(activity.getApplication(),viewModelClass);
}
/**
* 獲取只在本頁面唯一的ViewModel(一般用於保存頁面狀態,比如橫豎屏切換後要恢復狀態)
* @param application 本項目所設置使用的application實體
* @param viewModelClass ViewModel對應的類
* @param owner 一般就是AppCompatActivity或Fragment
* @return
*/
public static <T extends ViewModel> T getPrivateViewModel(Application application, Class<T> viewModelClass,ViewModelStoreOwner owner){
ViewModelProvider.Factory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
return new ViewModelProvider(owner, factory).get(viewModelClass);
}
public static <T extends ViewModel> T getPrivateViewModel(Activity activity, Class<T> viewModelClass,ViewModelStoreOwner owner){
return getPrivateViewModel(activity.getApplication(),viewModelClass,owner);
}
public static <T extends ViewModel> T getPrivateViewModel(Fragment fragment, Class<T> viewModelClass,ViewModelStoreOwner owner){
return getPrivateViewModel(fragment.getActivity(),viewModelClass,owner);
}
}