1.介紹
ViewModel,意為 視圖模型廊宪,即 為界面準(zhǔn)備數(shù)據(jù)的模型族奢。就是ViewModel為UI層提供數(shù)據(jù)。
官方文檔定義如下:
- ViewModel 以注重生命周期的方式存儲(chǔ)和管理界面相關(guān)的數(shù)據(jù)。(作用)
- ViewModel 類讓數(shù)據(jù)可在發(fā)生屏幕旋轉(zhuǎn)等配置更改后繼續(xù)留存抱慌。(特點(diǎn))
作用: - 因配置更改導(dǎo)致頁面重建后可以保存頁面數(shù)據(jù)
- ViewModel不持有View 在數(shù)據(jù)變更的時(shí)候通知View數(shù)據(jù)變更
- ViewModel的生命周期與Activity的生命周期綁定逊桦,可以有效的防止內(nèi)存泄露
2.ViewModel使用 - 繼承ViewModel自定義MyViewModel
- 在MyViewModel中編寫獲取UI數(shù)據(jù)的邏輯
- 使用LiveData將獲取到的UI數(shù)據(jù)拋出
- 在Activity/Fragment中使用ViewModelProvider獲取MyViewModel實(shí)例
- 觀察MyViewModel中的LiveData數(shù)據(jù),進(jìn)行對(duì)應(yīng)的UI更新抑进。
public class UserViewModel extends ViewModel {
private MutableLiveData<String> userLiveData ;
private MutableLiveData<Boolean> loadingLiveData;
public UserViewModel() {
userLiveData = new MutableLiveData<>();
loadingLiveData = new MutableLiveData<>();
}
//獲取用戶信息,假裝網(wǎng)絡(luò)請(qǐng)求 2s后 返回用戶信息
public void getUserInfo() {
loadingLiveData.setValue(true);
new AsyncTask<Void, Void, String>() {
@Override
protected void onPostExecute(String s) {
loadingLiveData.setValue(false);
userLiveData.setValue(s);//拋出用戶信息
}
@Override
protected String doInBackground(Void... voids) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String userName = "......";
return userName;
}
}.execute();
}
public LiveData<String> getUserLiveData() {
return userLiveData;
}
public LiveData<Boolean> getLoadingLiveData() {
return loadingLiveData;
}
}
UserViewModel繼承ViewModel强经,然后邏輯很簡單:假裝網(wǎng)絡(luò)請(qǐng)求 2s后 返回用戶信息,其中userLiveData用于拋出用戶信息寺渗,loadingLiveData用于控制進(jìn)度條顯示匿情。
在看UI層
public class UserActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
Log.i(TAG, "onCreate: ");
TextView tvUserName = findViewById(R.id.textView);
ProgressBar pbLoading = findViewById(R.id.pb_loading);
//獲取ViewModel實(shí)例
ViewModelProvider viewModelProvider = new ViewModelProvider(this);
UserViewModel userViewModel = viewModelProvider.get(UserViewModel.class);
//觀察 用戶信息
userViewModel.getUserLiveData().observe(this, new Observer<String>() {
@Override
public void onChanged(String s) {
// update ui.
tvUserName.setText(s);
}
});
userViewModel.getLoadingLiveData().observe(this, new Observer<Boolean>() {
@Override
public void onChanged(Boolean aBoolean) {
pbLoading.setVisibility(aBoolean?View.VISIBLE:View.GONE);
}
});
//點(diǎn)擊按鈕獲取用戶信息
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
userViewModel.getUserInfo();
}
});
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
頁面有個(gè)按鈕用于點(diǎn)擊獲取用戶信息,有個(gè)TextView展示用戶信息信殊。 在onCreate()中先 創(chuàng)建ViewModelProvider實(shí)例炬称,傳入的參數(shù)是ViewModelStoreOwner,Activity和Fragment都是其實(shí)現(xiàn)涡拘。然后通過ViewModelProvider的get方法 獲取ViewModel實(shí)例玲躯,然后就是 觀察ViewModel中的LiveData。
源碼分析
我們主要分析一個(gè)部分 ViewModel是如何存儲(chǔ)數(shù)據(jù)的鳄乏,以為什么頁面的重建不會(huì)導(dǎo)致數(shù)據(jù)丟失跷车。
public abstract class ViewModel {
...
private volatile boolean mCleared = false;
//在ViewModel將被清除時(shí)調(diào)用
//當(dāng)ViewModel觀察了一些數(shù)據(jù),可以在這里做解注冊(cè) 防止內(nèi)存泄漏
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
@MainThread
final void clear() {
mCleared = true;
...
onCleared();
}
...
}
ViewModel類 是抽象類橱野,內(nèi)部沒有啥邏輯朽缴,有個(gè)clear()方法會(huì)在ViewModel將被清除時(shí)調(diào)用。
然后ViewModel實(shí)例的獲取是通過ViewModelProvider類水援,見名知意密强,即ViewModel提供者,來看下它的構(gòu)造方法: