ViewModel
/**
ViewModel是一個負責準備和管理Activity或Fragment數據的類。
它還處理Activity / Fragment與其他應用程序的通信 (例如調用業務邏輯類)
ViewModel會在一個關聯的范圍內(activity 或者 fragment)創建,只要activity或fragment是活著的,它將被保留.
換句話說,這意味著如果它的所有者由于配置改變被銷毀了(例如旋轉), ViewModel不會被銷毀,所有者的新實例將重新連接到現有的ViewModel。
ViewModel的目的是獲取并保存Activity或Fragment所需的信息. Activity或Fragment應該能夠觀察ViewModel中的變化。ViewModel通常通過LiveData或Android DataBinding公開這些信息。 你也可以使用你喜歡的框架的任何可觀察性構造。
ViewModel唯一的職責就是管理用戶界面的數據, 它不應該訪問您的視圖層次結構或持有引用回到Activity或Fragment.
典型的用法:
* public class UserActivity extends Activity {
*
* {@literal @}Override
* protected void onCreate(Bundle savedInstanceState) {
* super.onCreate(savedInstanceState);
* setContentView(R.layout.user_activity_layout);
* final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
* viewModel.userLiveData.observer(this, new Observer<User>() {
* {@literal @}Override
* public void onChanged(@Nullable User data) {
* // update ui.
* }
* });
* findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
* {@literal @}Override
* public void onClick(View v) {
* viewModel.doAction();
* }
* });
* }
* }
ViewModel:
* public class UserModel extends ViewModel {
* public final LiveData<User> userLiveData = new LiveData<>();
*
* public UserModel() {
* // trigger user load.
* }
*
* void doAction() {
* // depending on the action, do necessary business logic calls and update the
* // userLiveData.
* }
* }
ViewModels也可以用作Activity中的不同Fragment之間的通信層。 每個Fragment可以通過他們的Activity使用相同的密鑰來獲取ViewModel。這允許Fragment之間以分離的方式進行通信,使得它們不需要直接與另一個Fragment進行通信。
* public class MyFragment extends Fragment {
* public void onStart() {
* UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);
* }
* }
*/
public abstract class ViewModel {
/**
* 這個ViewModel被銷毀時調用
* <p>
* It is useful when ViewModel observes some data and you need to clear this subscription to
* prevent a leak of this ViewModel.
*/
@SuppressWarnings("WeakerAccess")
protected void onCleared() {
}
}
ViewModelProviders.of(this).get(MyViewModel::class.java)
// ViewModelProviders
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
// 確保單例對象 sDefaultFactory 實例存在
initializeFactoryIfNeeded(checkApplication(activity));
return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
}
// ViewModelStores
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
// 創建HolderFragment 并且添加到Activity當中, 返回ViewModelStore
return HolderFragment.holderFragmentFor(activity).getViewModelStore();
}
// HolderFragment
// getViewModelStore() 返回該實例
private ViewModelStore mViewModelStore = new ViewModelStore();
private static final HolderFragmentManager sHolderFragmentManager = new HolderFragmentManager();
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
public static HolderFragment holderFragmentFor(FragmentActivity activity) {
return sHolderFragmentManager.holderFragmentFor(activity);
}
// HolderFragmentManager
HolderFragment holderFragmentFor(FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
// 根據 HOLDER_TAG 尋找 HolderFragment
HolderFragment holder = findHolderFragment(fm);
if (holder != null) {
return holder;
}
// mNotCommittedActivityHolders 保存已經執行了add操作, 但是沒有添加進去的 Fragment
holder = mNotCommittedActivityHolders.get(activity);
if (holder != null) {
return holder;
}
if (!mActivityCallbacksIsAdded) {
mActivityCallbacksIsAdded = true;
// 在activity的 onDestroy()方法中 mNotCommittedActivityHolders釋放引用
activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
}
// 創建 HolderFragment 添加到當前 Activity 當中
holder = createHolderFragment(fm);
// 上面方法執行了 fragment 的 add以及commit 操作, 到HolderFragment 真正添加到activity之前記錄
mNotCommittedActivityHolders.put(activity, holder);
return holder;
}
// HolderFragment
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
sHolderFragmentManager.holderFragmentCreated(this);
}
// HolderFragmentManager
void holderFragmentCreated(Fragment holderFragment) {
// 如果是在Fragment中嵌套Fragment, 該返回不為空, 這里只討論Activity的情況
Fragment parentFragment = holderFragment.getParentFragment();
if (parentFragment != null) {
mNotCommittedFragmentHolders.remove(parentFragment);
parentFragment.getFragmentManager().unregisterFragmentLifecycleCallbacks(
mParentDestroyedCallback);
} else {
// 執行 onCreate() 說明HolderFragment以及添加到Activity, 可以釋放引用了
mNotCommittedActivityHolders.remove(holderFragment.getActivity());
}
}
@NonNull
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@NonNull
@MainThread
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.
}
}
// 根據反射創建實例
viewModel = mFactory.create(modelClass);
// 存入 viewModel實例
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
到這里會發現只是將一個毫不起眼的HolderFragment添加到Activity,并且利用HolderFragment中的ViewModelStore中的Map保存了 自定義ViewModel實例.
HolderFragment是如何在在Activity配置變更被銷毀時繼續持有viewModel的?
// HolderFragment
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 這行代碼上面已經分析過了
sHolderFragmentManager.holderFragmentCreated(this);
}
@Override
public void onDestroy() {
super.onDestroy();
// 調用ViewModel的
mViewModelStore.clear();
}
// ViewModelStore
public final void clear() {
for (ViewModel vm : mMap.values()) {
// 空方法, 繼承給開發者用, 做釋放等操作
vm.onCleared();
}
// 清空map, 也就是 釋放ViewModel數據
mMap.clear();
}
上面也并沒有什么特殊的操作, 并且在onDestroy() 中釋放了 viewModel, 那么在 Activity例如旋轉的時候會調用onDestroy(), 跟著 Fragment的 onDestroyView(), onDestroy(), onDetach() 會依次觸發. HolderFragment為什么不會調用 onDestroy()?
關鍵來了!!
// 關鍵就在 HolderFragment的構造方法中
public HolderFragment() {
setRetainInstance(true);
}
// Fragment
/**
控制是否在重新創建Activity(例如配置更改)中保留Fragment實例。這只能用于不在back stack中的Fragment。 如果設置,則在 recreate Activity時,Fragment生命周期將略有不同:
onDestroy() 將不會被調用 (但onDetach() 仍然會,因為片段正在從它當前的活動分離). onCreate(Bundle)將不會被調用,因為片段不被重新創建。onAttach(Activity) 和 onActivityCreated(Bundle)仍然被調用。
*/
public void setRetainInstance(boolean retain) {
mRetainInstance = retain;
}
所以在ViewModel類的注釋中有一段
ViewModel唯一的職責就是管理用戶界面的數據, 它不應該訪問您的視圖層次結構或持有引用回到Activity或Fragment.
一旦ViewModel持有了Activity, 并且在旋轉時, 新的Activity需要創建, 而舊的Activity需要被釋放. 但是被ViewModel持有而釋放不了就有可能造成內存泄漏.