- Android資料繫結技術一,企業級開發
- Android資料繫結技術二,企業級開發
- Android JetPack~ DataBinding(資料繫結)(一) 整合與使用
- Android JetPack~ LiveData (一) 介紹與使用
- Android JetPack~ ViewModel (一) 介紹與使用
- Android JetPack Room(一) 介紹與使用
ViewModel,MVVM框架中的一部分,他主要作用是處理業務邏輯、資料分配等,他是Mode和VIew連線的橋樑,和MVP相比,他類似P。
ViewModel類有如下優點:
- ViewModel類是具有生命感知的能力,與和他繫結的Activity一樣的生命週期,它可以解決請求網路時,Activity被突然銷燬造成一些不必要的麻煩。
- 裝置資訊發生變更資料不會丟失(切橫豎屏),其實它只有一個生命週期,檢測頁面銷燬時觸發
- ViewModel 的另一個特點就是同一個 Activity 的 Fragment 之間可以使用ViewModel實現共享資料。
- 每個Activity繫結的ViewModel都是獨立的(Activity之間)
沒用的小忠告
有些問題,可能沒有深度。
有一次一個面試官問我,Q:你知道ViewModel是如何和Acvitity繫結的嗎?我當時大腦在想1、他是不是問我內部實現?2、簡單用法?我猜是第一,不然第二種的話,有啥可問的。當時我說:我不知道。他詫異的看著我,你不是使用過MVVM框架嗎?不知道怎麼用ViewModel嗎。我不自信的說了句是透過ViewModelProvider。他來了一句是,是這個,後面問了我好多很簡單的問題,當時給我整無語了,怎麼全是這咋用,那咋用,一點深度都沒有,卻給我搞的很不自信,因為好多使用步驟平常不復習,就很容易忘,我當時就覺得這小子水平估計也不咋樣,離場後果斷刪除了他們人事的聯絡方式。
1、開始使用
新增依賴
以前是需要新增依賴的,現在
方式一: implementation 'androidx.appcompat:appcompat:1.2.0',//這裡面也包含ViewModel,LiveData等,
方式二: 也可以單獨新增
implementation "androidx.fragment:fragment:1.1.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:2.1.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
2、Activity
2.1、新建ViewModel
public class MyViewModel extends ViewModel {
@Override
protected void onCleared() {
super.onCleared();
}
}
onCleared方法是ViewModel獨有的,當Activity銷燬後,它會呼叫,所以我們可以在這取消網路請求等。平常開發中不做任何操作時,如果有網路請求中,Activity被銷燬,那麼極有可能請求成功返回結果到activity中造成洩漏等不必要的麻煩。
解決方式:
可以使用ViewModel,結合onCleared(),call.cancel()等去做。
網路請求時,突然銷燬activity,那麼與之繫結的viewmodel也會銷燬,同時我們在onCleared()方法中取消網路連線介面(call.cancel()),就算是有資料返回,activity也不會收到通知,因為資料是從livedata中監聽的,只有livedata觸發了更新,Activity才會收到通知。
(當然還有很多其他方式)
2.2、繫結Activity
這裡有如下方式:
- ViewModelProviders.of(this).get(class)(過時)
- new ViewModelProvider(this,factory).get(class)(常用)
- new ViewModelProvider.NewInstanceFactory().create(class);
第一種方式:ViewModelProviders.of(this).get(class)
ViewModelProviders.of(this).get(MyViewModel.class);
implementation "androidx.fragment:fragment:1.1.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:2.1.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
這種方式是這些依賴中的,當然,如果你的和我的不一樣,也無所謂,這不是重點。這個方式比較老了,在原始碼中也能發現,ViewModelProviders的of方法其實也是呼叫了ViewModelProvider,自動建立了一個factory。
----------------ViewModelProviders.class----------------
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
Application application = checkApplication(checkActivity(fragment));
if (factory == null) {
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
return new ViewModelProvider(fragment.getViewModelStore(), factory);
}
第二種方式:new ViewModelProvider(this,factory).get(class)
ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
傳入一個系統的factory。create是建立一個新的例項,而get是先從HashMap中找,找不到就建立新的例項。也是為什麼重建的Viewmodel是同一個物件的原因,他會把物件放在ViewModelStore類中HashMap<String, ViewModel> mMap = new HashMap<>();中。這個方式比較新,一般也是這樣建立。
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
//第一步:先查詢
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
//第二步:沒有則建立,並儲存在mViewModelStore中
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
第三種方式:new ViewModelProvider.NewInstanceFactory().create(class);
MyViewModel myViewModel1 = new ViewModelProvider.NewInstanceFactory().create(MyViewModel.class);
下面寫一個LiveData,如果對LiveData不懂的可以翻看之前的部落格,目錄在頂部
public class MyViewModel extends ViewModel {
private MutableLiveData<String> mStr= new MutableLiveData<>();
public MutableLiveData<String> getmStr() {
return mStr;
}
public void setmStr(String s) {
if(mStr==null){
mStr = new MutableLiveData<>();
}
mStr.setValue(s);
}
@Override
protected void onCleared() {
super.onCleared();
}
}
全部程式碼
public class JPackActivity extends AppCompatActivity {
private ActyJpackLayoutBinding mBinding;
private MyViewModel myViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//透過databinding 把activity和view繫結
mBinding = DataBindingUtil.setContentView(this,R.layout.acty_jpack_layout);
//透過ViewModeProvider 把activity和ViewModel繫結起來。
myViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
myViewModel.getmStr().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
mBinding.textShow.setText(s);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
//移除觀察者
}
3、Fragment
使用和Activity中一樣。不過需要注意的是傳入this和getActivity的區別
- this:這個ViewModel是獨立的,只為這個Fragment單獨服務,其他Fragment無法獲取到相同記憶體地址的ViewModel
- getActivity:使用getActivity()獲得的ViewModel 作用域在Activity裡和所有他建立碎片的裡,意思是你在其他Fragment也獲取相同記憶體地址的ViewModel
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
MyViewModel myViewModel = new ViewModelProvider(getActivity(), new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
return inflater.inflate(R.layout.fragment_blank, container, false);
}
當然還有一個注意點get("key1",MyViewModel.class);,get方法可以傳key值,不同的key建立的ViewModel資料是獨立的
4、總結
使用起來非常簡單,還要多加練習,才不會被那些xx面試官問步驟咋實現難住。