熟悉mvp模式的小伙伴应该都清楚,m->Model,v->View,p->presenter, p层调用model层的业务处理,将结果通过接口返回给View层,而此处所介绍的ViewModel用法有点类似与p层,只不过你要把业务处理放在这个ViewModel中,那么它就不那么像p层了,反正设计模式在于你怎么用,灵活运用,可以创造很多类似,但又超过类似。假如ViewModel中写入网络调用,之后将结果通过LiveData将数据回调给视图层Activity或Frament,看LiveData名字的意思就是(活跃的数据),故名思议,如果在网络调用中,突然按了返回键的话,ui更新的接口就不会被调用,因为这时检查出,Activity或Frament生命周期走到尽头,所以说此时数据是不活跃的,那么就没有必要更新ui接口了。说了这么多,先看一下这两个类的具体用法:
public class LoginViewModel extends AndroidViewModel {
MutableLiveData loginString=new MutableLiveData();
然后写一个goLogin方法用于模拟登陆
public void goLogin(){
ArrayMap params = new ArrayMap();
params.put("username", "18768156795");
params.put("password","123456");
OkhttpHelp.postUrl("https://chat.yggx.com/login/check").OnUIThread().params(params).post(new StringResultCallBack() {
@Override
public void onError(Request request, Exception e) {
}
@Override
public void onResponse(String response) {
// loginString.setValue(response);
loginString.setValue(response);
} }); }
private LoginViewModel model=new LoginViewModel(getApplication());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layout.activity_main);
getLifecycle().addObserver(new ActivityDaiLi());
model.loginString.observe(this, new Observer() {
@Override
public void onChanged(@Nullable String s) {
Log.i("huoying",s);
}
});
model.goLogin();
}
这里注意一下LiveData的setValue方法,必须在UI线程中执行,当然这里的登陆返回消息需要客户端自己解析,那么如果换成一个接口更新多个UI控件的话,可以用LiveData的间接子类MediatorLiveData,如下代码
public void login1(LifecycleOwner owner) {
/* LiveData data1= Transformations.switchMap(loginString1, new Function>() {
@Override
public LiveData apply(String input) {
liveData=new MutableLiveData() ;
return liveData;
}
});
loginString1.setValue("ww");
liveData.setValue(6);*/
data.observe(owner, new Observer() {
@Override
public void onChanged(@Nullable String s) {
String h = s.substring(1);
String h1 = s.substring(1);
Log.i("huoying", s + "");
loginString1.setValue(h + "");
}
});
ArrayMap params = new ArrayMap();
params.put("username", "18768156795");
params.put("password", "123456");
OkhttpHelp.postUrl("https://chat.yggx.com/login/check").OnUIThread().params(params).post(new StringResultCallBack() {
@Override
public void onError(Request request, Exception e) {
}
@Override
public void onResponse(String response) {
data.setValue(response);
}
});
}
MediatorLiveData data=new MediatorLiveData();
data.addSource(loginString1, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.i("huoying",o +"");
}
});
data.observe(owner, new Observer() {
@Override
public void onChanged(@Nullable String s) {
String h = s.substring(1);
String h1 = s.substring(1);
Log.i("huoying", s + "");
loginString1.setValue(h + "");
}
});
首先一般网络数据返回的是json格式,那么假如我们有两个TextView1、TextView1它们需要分别显示json数据当中的一个字段,那么完全可以在这个方法中解析json,
此处只是模拟了截取代替解析,那么将TextView想要的数据通过loginString1.setValue(h + "")设置回去,那么将会调用下面这个回调方法
data.addSource(loginString1, new Observer() {
@Override
public void onChanged(@Nullable Object o) {
Log.i("huoying",o +"");
}
});
在此处操作控件,也就是说什么控件需要什么数据完全可以用LiveData的回调方法进行回调绑定,存在一种数据包括多个控件的更新的话,完全可以用MediatorLiveData进行管理拆分。故名思议,MediatorLiveData的用法就是将一种数据如果可以的话拆分成我们想要的数据并跟不同控件进行绑定。当然,如果你嫌弃用MediatorLiveData麻烦的话可以直接用Transformations这个工具类,它直接提够了map和switchMap两个方法帮你返回MediatorLiveData对象。
看到这是不是感觉先出的这个框架确实用起来很爽,完全的隔离了UI和数据的操作,并保证了只有窗体被认为存活的话才会更新ui控件,否则没有必要或者避免一些错误,如果把上面的用法结合mvp和mvvm的话,会更显得代码高端大气上档次有木有。好了,既然已经会用了,那么接下来分析这两个类的源码怎么写的。
首先来看一下AndroidViewModel
public class AndroidViewModel extends ViewModel {
@SuppressLint("StaticFieldLeak")
private Application mApplication;
public AndroidViewModel(@NonNull Application application) {
mApplication = application;
}
/**
* Return the application.
*/
@NonNull
public T getApplication() {
//noinspection unchecked
return (T) mApplication;
}
}
public abstract class ViewModel {
/**
* This method will be called when this ViewModel is no longer used and will be destroyed.
*
* 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() {
}
}
public class MutableLiveData extends LiveData {
@Override
public void postValue(T value) {
super.postValue(value);
}
@Override
public void setValue(T value) {
super.setValue(value);
}
public class MediatorLiveData extends MutableLiveData {
private SafeIterableMap, Source>> mSources = new SafeIterableMap<>();
/**
* Starts to listen the given {@code source} LiveData, {@code onChanged} observer will be called
* when {@code source} value was changed.
*
* {@code onChanged} callback will be called only when this {@code MediatorLiveData} is active.
*
If the given LiveData is already added as a source but with a different Observer,
* {@link IllegalArgumentException} will be thrown.
*
* @param source the {@code LiveData} to listen to
* @param onChanged The observer that will receive the events
* @param The type of data hold by {@code source} LiveData
*/
@MainThread
public void addSource(@NonNull LiveData source, @NonNull Observer onChanged) {
Source e = new Source<>(source, onChanged);
Source> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
/**
* Stops to listen the given {@code LiveData}.
*
* @param toRemote {@code LiveData} to stop to listen
* @param the type of data hold by {@code source} LiveData
*/
@MainThread
public void removeSource(@NonNull LiveData toRemote) {
Source> source = mSources.remove(toRemote);
if (source != null) {
source.unplug();
}
}
@CallSuper
@Override
protected void onActive() {
for (Map.Entry, Source>> source : mSources) {
source.getValue().plug();
}
}
@CallSuper
@Override
protected void onInactive() {
for (Map.Entry, Source>> source : mSources) {
source.getValue().unplug();
}
}
private static class Source implements Observer {
final LiveData mLiveData;
final Observer mObserver;
int mVersion = START_VERSION;
Source(LiveData liveData, final Observer observer) {
mLiveData = liveData;
mObserver = observer;
}
void plug() {
mLiveData.observeForever(this);
}
void unplug() {
mLiveData.removeObserver(this);
}
@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
}
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
LifecycleBoundObserver existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && existing.owner != wrapper.owner) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
public interface GenericLifecycleObserver extends LifecycleObserver {
class LifecycleBoundObserver implements GenericLifecycleObserver
static GenericLifecycleObserver getCallback(Object object) {
if (object instanceof FullLifecycleObserver) {
return new FullLifecycleObserverAdapter((FullLifecycleObserver) object);
}
if (object instanceof GenericLifecycleObserver) {
return (GenericLifecycleObserver) object;
}.....
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(observer);
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
activeStateChanged(isActiveState(owner.getLifecycle().getCurrentState()));
}
这里首先判断当前activity是否已经被销毁,如果被销毁根本没有必要通知数据改变,举个例子如果你用Frament在网络调用成功的回调方法中进行Activity的跳转,getActivity().StartActivity时,有时会发生getActivity()为null的现象,造成这种现象的原因是提前结束activity,这里只能加一个getActivity是否为null的判断或者if(add())判断。那么以上这个判断就是上了第一道安全锁,接着就是isActiveState方法
static boolean isActiveState(State state) {
return state.isAtLeast(STARTED);
}
void activeStateChanged(boolean newActive) {
if (newActive == active) {
return;
}
active = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += active ? 1 : -1;
if (wasInactive && active) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !active) {
onInactive();
}
if (active) {
dispatchingValue(this);
}
}
}
private void dispatchingValue(@Nullable LifecycleBoundObserver initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
if (initiator != null) {
considerNotify(initiator);
initiator = null;
} else {
for (Iterator, LifecycleBoundObserver>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
private void considerNotify(LifecycleBoundObserver observer) {
if (!observer.active) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
if (!isActiveState(observer.owner.getLifecycle().getCurrentState())) {
observer.activeStateChanged(false);
return;
}
if (observer.lastVersion >= mVersion) {
return;
}
observer.lastVersion = mVersion;
//noinspection unchecked
observer.observer.onChanged((T) mData);
}