Android ViewModel的使用

ViewModel的作用是爲界面準備數據,數據的獲取操作(如網絡請求)或者一些數據處理可以在該類中編寫方法,減少在Activity的代碼。

ViewModel裏面的數據可以分爲以下三類。

  1. 普通數據,只是負責保存數據,無特別作用,可當做普通類來用
    public class DataViewModel extends ViewModel {
        public String name;
        public int age;
    }

     

  2. 與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;
        }
    }

     

  3. 與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的實體對象(我發佈這篇文章時,中文官網展示的方法還是舊版的,以下的代碼已經是修改後的最新方法,舊版方法已拋棄。無法保證以後版本更新會不會有新的創建方法,如以後發現代碼報錯,可去官網看最新代碼)。

  1. 這種方法獲取的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);
        }
    }
  2. 這種方法獲取的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);
    }
}

 

發佈了111 篇原創文章 · 獲贊 21 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章