1.ViewModel是什么
ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
注意:ViewModel 绝不能引用视图、Lifecycle 或可能存储对 Activity 上下文的引用的任何类。
ViewModel 存在的时间范围是从您首次请求 ViewModel 直到 Activity 完成并销毁或者在 Fragment 分离时。
2.有什么用
- 解耦:
让视图(activity,fragment)分离出数据,更专注于展示数据和用户交互,数据处理则在viewmodle中完成。 - 数据不丢失:
viewmodel可以解决如屏幕旋转导致瞬态界面相关数据的丢失或者onSaveInstanceState()仅适合可以序列化再反序列化的少量数据的问题。 - 避免潜在的内存泄漏:
对于异步调用,如网络请求在activity中接收,可能潜在内存泄漏。而放在viewmodel则可规避。 - 在 Fragment 之间共享数据
Activity 不需要执行任何操作,也不需要对此通信有任何了解。
除了共享的ViewModel 约定之外,Fragment 不需要相互了解。如果其中一个 Fragment 消失,另一个 Fragment 将继续照常工作。
每个 Fragment 都有自己的生命周期,而不受另一个 Fragment 的生命周期的影响。如果一个 Fragment 替换另一个 Fragment,界面将继续工作而没有任何问题。
3.怎么用
class MyViewModel : ViewModel() {
private val users: MutableLiveData<List<User>> by lazy {
MutableLiveData().also {
loadUsers()
}
}
fun getUsers(): LiveData<List<User>> {
return users
}
private fun loadUsers() {
// fetch users.
}
}
class MyActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
val model: MyViewModel by viewModels()
model.getUsers().observe(this, Observer<List<User>>{ users ->
// update UI
})
}
}
个人理解:
使数据从页面中分离出来,不用再太注重页面的生命周期导致的数据丢失问题。
源码延展:
MyViewModel model = new ViewModelProvider(this).get(MyViewModel.class);
从上句代码作为入口。
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
: NewInstanceFactory.getInstance());
}
AppCompatActivity子类实现了ViewModelStoreOwner
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
mFactory = factory;
mViewModelStore = store;
}
@NonNull
@MainThread
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);
}
返回一个现有的ViewModel或在范围内创建一个新的ViewModel(fragment/activity),前提条件是ViewModel还是活动的(如果是一个activity,知道 finished 或者进程被杀)
private final Factory mFactory;
private final ViewModelStore mViewModelStore;
再看ViewModelStore 。是从owner.getViewModelStore()而来,进入owner
public interface ViewModelStoreOwner {
/**
* Returns owned {@link ViewModelStore}
*
* @return a {@code ViewModelStore}
*/
@NonNull
ViewModelStore getViewModelStore();
}
public class ViewModelStore {
private final HashMap<String, ViewModel> mMap = new HashMap<>();
final void put(String key, ViewModel viewModel) {
ViewModel oldViewModel = mMap.put(key, viewModel);
if (oldViewModel != null) {
oldViewModel.onCleared();
}
}
final ViewModel get(String key) {
return mMap.get(key);
}
Set<String> keys() {
return new HashSet<>(mMap.keySet());
}
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
ViewModelStore 使用 HashMap 保存 ViewModel
简单来说就是activity实现ViewModelStoreOwner,通过ViewModelStoreOwner的getViewModelStore()获取可以保存ViewModel的ViewModelStore。至于它们的作用范围scope不在此章展开