Activity/Fragment只应关注UI,而不应关系操作逻辑,因此操作逻辑应放到Viewmodel中去
下面是我手画的数据流图:
首先有Fragment
、ViewModel
、Livedata
这三个对象。
代码如下:
Fragment
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
/**
*
* @date 2020/9/19
*/
public class MyActivity extends AppCompatActivity {
Handler messageHandler;
MyViewModel myViewModel;
Handler mainHandler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = findViewById(R.id.textView);
// 新建ViewModel
myViewModel = new MyViewModel();
// 子线程
HandlerThread handlerThread = new HandlerThread("");
handlerThread.start();
// 子线程Handler
messageHandler = new Handler(handlerThread.getLooper());
// 主线程handler
mainHandler = new Handler(getMainLooper());
// 开启自自线程改变数据
messageHandler.post(new Runnable() {
@Override
public void run() {
int i = 0;
while (i < 100) {
mainHandler.post(new Runnable() {
@Override
public void run() {
myViewModel.requestChangeText();
}
});
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
});
myViewModel.getmText().observe(this, new Observer() {
@Override
public void onChanged(final String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(s);
}
});
}
});
}
}
viewmodel
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import java.util.Observable;
import java.util.Random;
/**
* Describe:
* 描述:
*
* @date 2020/9/19
*/
public class MyViewModel extends ViewModel implements IMyModelHelper {
private MutableLiveData mText = new MutableLiveData();
public MyViewModel() {
}
public MutableLiveData getmText() {
return mText;
}
@Override
public void requestChangeText() {
changeText();
}
private void changeText(){
getmText().setValue(new Random(10).toString());
}
}
package com.loyal888.tets;
/**
* Describe:
* 描述:
*
* @date 2020/9/19
*/
public interface IMyModelHelper {
void requestChangeText();
}
总结:数据通知可以使用Observer,实现进一步解耦合
// 新建ViewModel
myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
系统首次调用 Activity 对象的 onCreate() 方法时请求 ViewModel。系统可能会在 Activity 的整个生命周期内多次调用 onCreate(),如在旋转设备屏幕时。ViewModel 存在的时间范围是从您首次请求 ViewModel 直到 Activity 完成并销毁。
ViewModel 对象可以包含 LifecycleObservers,如 LiveData 对象。但是,ViewModel 对象绝不能观察对生命周期感知型可观察对象(如 LiveData 对象)的更改。 如果 ViewModel 需要 Application 上下文(例如,为了查找系统服务),它可以扩展 AndroidViewModel 类并设置用于接收 Application 的构造函数,因为 Application 类会扩展 Context。
1. ViewModelProvider.of(this)
- 检查应用的上下文
- 构造了AndroidViewModelFactory
- 返回provider
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
return of(activity, null);
}
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
@Nullable Factory factory) {
// 1. 检查应用的上下文且必须是application
Application application = checkApplication(activity);
if (factory == null) {
// 2.构造了AndroidViewModelFactory
factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
// 3.返回provider
// 3.1 注意这里的activity.getViewModelStore()
return new ViewModelProvider(activity.getViewModelStore(), factory);
}
2. activity.getViewModelStore()
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
// 获取上一次配置改变保存的NonConfigurationInstances,比如屏幕旋转
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
// 配置改变,viewModelStore不空,直接使用
// 这个viewModelStore是在哪里保存的?见下文
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
// 第一次来就新建一个ViewModelStore,保存的上一次的状态
// 新建来之后保存到哪里?见下文
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
3.保存ViewModelStore
getLastNonConfigurationInstance();
保存呢? 调用的是ConponentActivity
中的onRetainNonConfigurationInstance
,调用时机介于onStop
和onDestroy
中间,onSaveInstance
之后。
public final Object onRetainNonConfigurationInstance() {
Object custom = onRetainCustomNonConfigurationInstance();
// 这里就是上文的new出来的mViewModelStore
ViewModelStore viewModelStore = mViewModelStore;
if (viewModelStore == null) {
// No one called getViewModelStore(), so see if there was an existing
// ViewModelStore from our last NonConfigurationInstance
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
viewModelStore = nc.viewModelStore;
}
}
if (viewModelStore == null && custom == null) {
return null;
}
NonConfigurationInstances nci = new NonConfigurationInstances();
nci.custom = custom;
// 把mViewModelStore保存到NonConfigurationInstances中去
nci.viewModelStore = viewModelStore;
return nci;
}
4. 获取上一次保存的viewmodel
public ViewModelStore getViewModelStore() {
if (getApplication() == null) {
throw new IllegalStateException("Your activity is not yet attached to the "
+ "Application instance. You can't request ViewModel before onCreate call.");
}
if (mViewModelStore == null) {
NonConfigurationInstances nc =
(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstances
// 注意上面这句英文
mViewModelStore = nc.viewModelStore;
}
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
}
return mViewModelStore;
}
5. 获取ViewModel
ViewModelProviders.of(this).get(MyViewModel.class);
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);
}
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
// 上文提到构建出来的mViewModelStore,从HashMap取出实例
ViewModel viewModel = mViewModelStore.get(key);
if (modelClass.isInstance(viewModel)) {
//noinspection unchecked
// 有就返回
return (T) viewModel;
} else {
//noinspection StatementWithEmptyBody
if (viewModel != null) {
// TODO: log a warning.
}
}
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
// 没有反射创建出来
viewModel = (mFactory).create(modelClass);
}
// 将mViewModelStore保存到HashMap,保存的时候会销毁旧对象
mViewModelStore.put(key, viewModel);
//noinspection unchecked
return (T) viewModel;
}
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) {
// 旧viewmodel会被清除!!!
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();
}
}
VieModelStore
存在于FragmentActivity
中,在配置更改导致Activity销毁前通过onRetainNonConfiguraionInstance
将数据对象保存,并在重建时通过getLastNonConfigurationInstance
将数据还原回来,从而保证了Activity内ViewModelStore 的唯一性
和一致性
。LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。
构造方法
public LiveData(T value) {
// 保存具体的值
mData = value;
// 当前版本
mVersion = START_VERSION + 1;
}
}
观察Livedata
myViewModel.getmText().observe(this, new Observer<String>() {
@Override
public void onChanged(final String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textView.setText(s);
}
});
}
});
observe了什么
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// mObservers 添加了当前观察者
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
数据改变setValue之后
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 通知并回调每一个观察者的回调方法
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
eg:
public static <X, Y> LiveData<Y> map(
@NonNull LiveData<X> source,
@NonNull final Function<X, Y> mapFunction) {
final MediatorLiveData<Y> result = new MediatorLiveData<>();
// X改变了,Y继续
result.addSource(source, new Observer<X>() {
@Override
public void onChanged(@Nullable X x) {
result.setValue(mapFunction.apply(x));
}
});
return result;
}
MutableLiveData userIdLiveData = ...;
LiveData userLiveData = Transformations.switchMap(userIdLiveData, id ->
repository.getUserById(id));
void setUserId(String userId) {
this.userIdLiveData.setValue(userId);
}
1 不需要手动处理生命周期
ViewModel和LiveData本身是生命周期可感知的
2 确保View可以及时拿到数据状态
LiveData遵循观察者模式,数据更改时,LiveData会通知对象。这也是它的优势,如果UI改变很多,MVP就需要写很多的接口。View被动的接受Presenter的指令。
3 减少内存泄漏
LiveData绑定了Lifecycle对象,ViewModel 在生命周期方法中自行清理回收
4 共享资源
单例使用ViewModel和LiveData,可以在程序中共享他们,例两个fragment共享一个ViewModel
1、建议添加LiveData和ViewModel的详细使用介绍,方便大家知道一些高级使用方式。比如LiveData对数据的拼装等。
2、文档不太能体现出和MVP的对比及优势。比如ViewModel和View解耦之类的。