Android Architecture Components应用架构组件源码详解(基于1.0以上)(第二篇ViewModel和LiveData)

来源:互联网 发布:开淘宝店物流怎么解决 编辑:程序博客网 时间:2024/06/06 10:03

熟悉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();

首先创建一个LoginViewModel这里模拟一个网络登陆,在这个类中声明一个MediatorLiveData,MediatorLiveData为LiveData的直接子类


然后写一个
goLogin方法用于模拟登陆

public void goLogin(){        ArrayMap<String, String> params = new ArrayMap<String, String>();        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); } }); }

最后activity中调用ViewModle的方法

 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<String>() {            @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<String, LiveData<Integer>>() {            @Override            public LiveData<Integer> apply(String input) {             liveData=new MutableLiveData<Integer>() ;                return liveData;            }        });        loginString1.setValue("ww");        liveData.setValue(6);*/        data.observe(owner, new Observer<String>() {            @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<String, String> params = new ArrayMap<String, String>();        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);            }        });    }

这里的data为

MediatorLiveData data=new MediatorLiveData();

然后再添加多个LiveData

data.addSource(loginString1, new Observer() {            @Override            public void onChanged(@Nullable Object o) {                Log.i("huoying",o +"");            }        });

首先调用登陆成功之后,主动调用data.setValue(response);方法,这个方法会导致下面这个回调方法的执行,那么在这里可以做一些事情了。

data.observe(owner, new Observer<String>() {            @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 extends Application> T getApplication() {        //noinspection unchecked        return (T) mApplication;    }}

类中方法很简单就是持有一个Application的引用,没啥好说的,接着是它的父类ViewModel

public abstract class ViewModel {    /**     * This method will be called when this ViewModel is no longer used and will be destroyed.     * <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() {    }}

完全的抽象方法,有一个onCleared方法,用户可以重写该方法进行数据的释放。

接下来看一看MutableLiveData的是怎么构造的

public class MutableLiveData<T> extends LiveData<T> {    @Override    public void postValue(T value) {        super.postValue(value);    }    @Override    public void setValue(T value) {        super.setValue(value);    }

就两个方法通知是否可以调用回调方法,就是上面说的onChanged方法,当然postValue和setValue区别就是postValue保证onChange方法在主线程中执行,而setValue会检查是否在主线程中执行,不在就抛异常。继续看MediatorLiveData类

public class MediatorLiveData<T> extends MutableLiveData<T> {    private SafeIterableMap<LiveData<?>, Source<?>> mSources = new SafeIterableMap<>();    /**     * Starts to listen the given {@code source} LiveData, {@code onChanged} observer will be called     * when {@code source} value was changed.     * <p>     * {@code onChanged} callback will be called only when this {@code MediatorLiveData} is active.     * <p> 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 <S>       The type of data hold by {@code source} LiveData     */    @MainThread    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged) {        Source<S> 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 <S>      the type of data hold by {@code source} LiveData     */    @MainThread    public <S> void removeSource(@NonNull LiveData<S> toRemote) {        Source<?> source = mSources.remove(toRemote);        if (source != null) {            source.unplug();        }    }    @CallSuper    @Override    protected void onActive() {        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {            source.getValue().plug();        }    }    @CallSuper    @Override    protected void onInactive() {        for (Map.Entry<LiveData<?>, Source<?>> source : mSources) {            source.getValue().unplug();        }    }    private static class Source<V> implements Observer<V> {        final LiveData<V> mLiveData;        final Observer<V> mObserver;        int mVersion = START_VERSION;        Source(LiveData<V> liveData, final Observer<V> 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);            }        }    }}

这个类的实现方法也比较少,addSource添加单个MutableLiveData,并为Observer添加Source包装类,并通过onActive和onInactive进行Observer的注册和取消,为后面拆分数据用,removeSource方法取消集合保存的Source。好这就是这几个类的基本组成了。
 一切的监听都是始于注册,看看LiveData的注册到底实现了那些东西。

 public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> 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);    }

这里的owner是什么,有没有熟悉的感觉,owner即为activity实现的接口类,好吧,如果你不熟悉请先看上一篇LifecycleObserver和LifecycleOwner源码详解,这里普通的Observer观察者类又被套上了一层LifecycleBoundObserver装饰类,最后通过Lifecycle将Observer注册给LifecycleRegistry,这就和上一篇内容连起来了,最后都是在Activity或Frament生命周期发生改变的时候回调LifecycleObserver的onStateChanged方法。只不过监听生命周期我们实现的是LifecycleObserver接口,而此处是实现了LifecycleObserver接口的子类LifecycleBoundObserver,如下代码

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;        }.....

看到了什么,如果这个LifecycleObserver是GenericLifecycleObserver直接用GenericLifecycleObserver,也就是说在Activity生命周期改变的时候回调的是LifecycleBoundObserver的onStateChanged方法,实现如下:

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);    }

用当前生命周期状态和STARTED状态做对比,只有当Activity的生命周期状态为onResumed或onSarted方法时isActiveState方法返回true,也就是说只有当Activity处在onResumed或onSarted时LiveData被认为是有效的,此时才会执行UI更新的回调,否则没有必要执行,也就是我们常说的数据绑定了生命周期。
 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);            }        }    }

根据上面分析的再来看这个方法就很简单了,首先判断当前的状态是否和上一次一致,一致则方法不执行,其次计算当前的mActiveCount存活数量,假如当前是存活的,那么调用onActive方法,否则调用onInactive方法,毕竟多个activity有可能共享同一个ViewModel的LiveData,这里加入了mActiveCount计数,只有当不存在一个LiveData存活时,回调onInactive,最后通过dispatchingValue分发事件处理。


 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<Map.Entry<Observer<T>, LifecycleBoundObserver>> iterator =                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {                    considerNotify(iterator.next().getValue());                    if (mDispatchInvalidated) {                        break;                    }                }            }        } while (mDispatchInvalidated);        mDispatchingValue = false;    }

这个方法的大体意思就是如果是通过setvalue主动通知调用回调方法的话initiator为null,循环遍历LiveData注册的观察者,如果是生命周期回调回来的话initiator不为null,直接调用considerNotify,不管哪种方式最后都会调用considerNotify方法。而mDispatchingValue参数确保多个Activity共享LiveData的时候一次只能有一个Activity操作的。

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);    }

最后调用的这个方法对observer状态再进行一次安全检查,注意这里有个版本判断bserver.lastVersion >= mVersion,只有当主动调用setValue时,版本mVersion才会加1,也就是说是生命周期改变的回调最终都不会执行到observer.observer.onChanged((T) mData),生命周期改变只会记录active的状态,而不会告诉UI该更新数据了,只有setValue时,Activity是处在onStart或onResumed时才会进行UI更新,俗话说你的Activity都死了,我还更新你的UI干鸟啊,这就是谷歌设计代码的精妙之处有木有。还记得那些年Frament的那些坑吗?有了这个神器以后再也不怕有这些坑了。


阅读全文
0 0
原创粉丝点击