在上篇博客中的ViewModel的计时器案例的基础上,我们使用LiveData对接口进行改写

1.LiveData是一个抽象类,不能直接使用。我们通常使用的是它的直接子类MutableLiveData,代码如下


<pre language="javascript" code_block="true">public class LiveDataViewModel extends ViewModel {

    private MutableLiveData<Integer> currentSecond;

    private Timer timer;

    private  int current;

    @Override

    protected void onCleared() {

        super.onCleared();

        //释放资源

        timer.cancel();

    }

    public LiveData<Integer> getCurrentSecond(){

        if(currentSecond == null){

            currentSecond = new MutableLiveData<>();

        }

        return  currentSecond;

    }

    //开始定时器

    public  void startTiming(){

        if(timer == null){

            current = 0;

            timer = new Timer();

            TimerTask timerTask = new TimerTask() {

                @Override

                public void run() {

                    if(currentSecond!=null){

                        currentSecond.postValue(current++);

                    }

                }

            };

            timer.schedule(timerTask,1000,1000);

        }

    }

    //关闭定时器

    public  void stopTiming(){

        timer.cancel();

    }

}

1234567891011121314151617181920212223242526272829303132333435363738394041

当开始定时器的时候,也就是我们数据资源发生变化的时候,我们需要调用livedata.postvalue方法,通知页面我们数据源已经发生了改变。至于为什么不用livedata.setValue方法,等下我们会说到。

2.接着我们在Activity中创建ViewModel,并监听ViewModel里面currentSecond数据的变化。


<pre language="javascript" code_block="true">public class LiveDataActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_live_data);

        iniComponent();

    }

    private void iniComponent() {

        //通过ViewModelProvider得到ViewModel

        final LiveDataViewModel viewModel = new ViewModelProvider(this).get(LiveDataViewModel.class);

        //得到ViewModel中的LiveData

        final MutableLiveData<Integer> liveData = (MutableLiveData<Integer>) viewModel.getCurrentSecond();

        //通过liveData.observer()观察ViewModel中数据的变化

        liveData.observe(this, new Observer<Integer>() {

            @Override

            public void onChanged(Integer integer) {

                //收到回调后更新UI界面

                TextView tv = findViewById(R.id.tv_texts);

                tv.setText("小鑫啊"+integer);

            }

        });

        //关闭定时器

        findViewById(R.id.btnReset).setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                //通过LiveData.setValue()/LiveData.postValue()

                //完成对ViewModel中数据的更新

                liveData.setValue(0);

                //关闭定时器

                viewModel.stopTiming();

            }

        });

        //计时开始

        viewModel.startTiming();

    }

}

1234567891011121314151617181920212223242526272829303132333435363738394041424344

在页面中,通过LiveData.observe()方法对LivaData所包装的数据进行观察。当我们数据源发生变化了(也就是我们想修改LivaData所包装的数据时),就可以通过LiveData.postValue/LiveData.setValue()来完成,然后onChanged方法就会收到我们修改之后的数据,我们就可以对UI进行更改了.

需要注意的是:postValue()方法用在非UI线程中,而setValue()方法用在UI线程中,这就是为什么我们在开始定时器的时候,需要调用postVaule()发送数据了(因为定时器是运行在非UI线程的).

image

运行结果如下:

image

LivaData的基本使用就到这里,是不是很简单啊! 接下来,就让我们来探讨下LiveData的原理吧!!!

[]( )LiveData的原理

======================================================================

我们知道LiveData是通过观察者模式实现的。当数据发送改变的时候,会回调Observer的onChanged(),接下来就让我们深入Observer方法的源码一探究竟

[]( )observe源码

====================================================================


<pre language="javascript" code_block="true"> @MainThread

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

        //判断当前wapper已经添加过,如果添加过就直接返回,否则返回null

        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;

        }

        //没有添加过,则添加wrapper

        owner.getLifecycle().addObserver(wrapper);

    }

123456789101112131415161718192021

从源码可以看出,Observer()方法接收的第一个参数是一个LifecleOwner对象,我们传入的是this,因为this的祖父类实现了这个接口,也正是LifecleOwner对象,LiveData才会具体生命周期感知能力。

首先, 通过owner.getLifecycle().getCurrentState()获取当前页面的状态,如果当前页面被销毁了,就直接返回,也就是说LiveData会自动清除与页面的关联。

[]( )LifecycleBoundObserver 源码

====================================================================================


<pre language="javascript" code_block="true"> class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {

        @NonNull

        final LifecycleOwner mOwner;

        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {

            super(observer);

            mOwner = owner;

        }

        @Override

        boolean shouldBeActive() {

            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);

        }

        @Override

        public void onStateChanged(@NonNull LifecycleOwner source,

                @NonNull Lifecycle.Event event) {

            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {

                removeObserver(mObserver);

                return;

            }

            activeStateChanged(shouldBeActive());

        }

1234567891011121314151617181920212223

当调用 LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer),本质是通过 ObserverWrapper将observer包装起来,得以LiveData能对生命周期状态得以进行监听,是通过onStateChanged和shouldBeActive方法

  1. shouldBeActive 这里调用LiftCycle的方法,表达如果当前生命周期的状态为onStart,onResume,onPause时 返回true,也就是说只有这三个状态可以接收数据更新。

  2. onStateChanged 是LifecycleEventObserver接口的方法,当生命周期发送变化的时候会回调它,如果当前生命周期状态是destory,就会直接移除观察者,否则就会调用activeStateChanged(shouldBeActive());方法激活观察者.

方法中的最后一行代码将observer与Activity的生命周期关联在一起。因此,LivaData能够感知页面的生命周期。

[]( )observer方法小结

=======================================================================

  1. 判断是否已经销毁,如果当前页面销毁,LiveData自动清除与页面的关联

  2. 用LifecycleBoundObserver 对observer进行一个包装

  3. 判断当前observer是否已经添加过,添加过就直接返回

  4. 将observer方法与Activity的生命周期进行关联

[]( )setValue方法

=====================================================================


<pre language="javascript" code_block="true"> @MainThread

    protected void setValue(T value) {

        assertMainThread("setValue");

        mVersion++;

        mData = value;

        dispatchingValue(null);

    }

1234567

setValue()中,首先 断言是主线程,这里的关键是dispatchingValue(null)方法


<pre language="javascript" code_block="true">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;

    }

1234567891011121314151617181920212223

只有处于active(激活)状态的观察者,这个方法就会把数据发送给它们。由于每次dispathchingValue传入的null,所以会走else这一部分代码, 这时候就会遍历所有的observer,最后通过调用considerNotify()将数据进行分发给所有的observer


<pre language="javascript" code_block="true">private void considerNotify(ObserverWrapper observer) {

        if (!observer.mActive) {

            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.

        //如果当前observer不是激活状态,也就是当前页面被destory,直接return.

        if (!observer.shouldBeActive()) {

            observer.activeStateChanged(false);

            return;

        }

        if (observer.mLastVersion >= mVersion) {

            return;

        }

        observer.mLastVersion = mVersion;

        observer.mObserver.onChanged((T) mData);

    }

1234567891011121314151617181920

只有出于活跃状态且数据是数据是最新的,才会去分发数据,最后回调到我们熟悉的onChanged()方法。

[]( )postValue方法

======================================================================


<pre language="javascript" code_block="true"> protected void postValue(T value) {

        boolean postTask;

        synchronized (mDataLock) {

            postTask = mPendingData == NOT_SET;

            mPendingData = value;

        }

        if (!postTask) {

            return;

        }

        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);

    }

1234567891011

postValue方法是可以在子线程(非UI线程)发送数据的,但是onChanged()方法始终是在主线程? 答案就在postToMainThread(mPostValueRunnable)方法中;


<pre language="javascript" code_block="true">private final Runnable mPostValueRunnable = new Runnable() {

        @SuppressWarnings("unchecked")

        @Override

        public void run() {

            Object newValue;

            synchronized (mDataLock) {

                newValue = mPendingData;

                mPendingData = NOT_SET;

            }

            setValue((T) newValue);

        }

    };

123456789101112

创建一个Handler将子线程中的任务发送到主线程去执行,其本质还是调用了setValue()方法

[]( )LiveData.observeForever()方法

======================================================================================

如果你想无论页面处于何种生命周期,setValue/postValue之后立刻回到数据。那么可以使用observerForever()方法,使用起来与observer()没有太大差别. 因为AlwaysActiveObserver没有实现GenericLifecycleObserver 接口,不能感应生命周期。

但是需要注意的是,在用完之后,一定要记得在onDestroy()方法中调用removeObserver()方法来停止对LiveData的观察,否则LiveData会一直处于激活状态,Activity则永远不会被系统自动回收,会造成内存泄露。

[]( )ViewModel+LiveData实现Fragment间的通信

===========================================================================================

我们已经知道,ViewModel能够将数据从Activity中剥离出来。只要Activity不被销毁,ViewModel会一直存储,并且独立于Activity的配置变化。

Fragment可以被看作Activty的子页面,即一个Activity中可以包含多个Fragment.这些Fragment彼此独立,但是又都属于同一个Activity.

基于ViewModel和Fragment组件的这些特性,我们可以利用LiveData,实现同一个Activity中的不同Fragment间的通信,因为不同的Fragment得到的都是同一个LiveData;

image

[]( )定义ViewModel和LiveData

===============================================================================



<pre language="javascript" code_block="true">public class SharedViewModel extends ViewModel {

    private MutableLiveData<String> content;

    @Override

    protected void onCleared() {

        super.onCleared();

        //释放资源

        content=  null;

    }

    public LiveData<String> getContent(){
### 尾声

面试成功其实都是必然发生的事情,因为在此之前我做足了充分的准备工作,不单单是纯粹的刷题,更多的还会去刷一些Android核心架构进阶知识点,**比如:JVM、高并发、多线程、缓存、热修复设计、插件化框架解读、组件化框架设计、图片加载框架、网络、设计模式、设计思想与代码质量优化、程序性能优化、开发效率优化、设计模式、负载均衡、算法、数据结构、高级UI晋升、Framework内核解析、Android组件内核等。**
![](https://s2.51cto.com/images/20210905/1630818923200200.jpg)

不仅有学习文档,视频+笔记提高学习效率,还能稳固你的知识,形成良好的系统的知识体系。这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。

![](https://s2.51cto.com/images/20210905/1630818923574664.jpg)

##### Android进阶学习资料库

一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!

![image](https://s2.51cto.com/images/20210905/1630818923960502.jpg)

##### 大厂面试真题

PS:之前因为秋招收集的二十套一二线互联网公司Android面试真题 (含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

![](https://s2.51cto.com/images/20210905/1630818924432883.jpg)

**《2017-2021字节跳动Android面试历年真题解析》**

![](https://s2.51cto.com/images/20210905/1630818924684837.jpg)

如果需要PDF版本可以自行领取!

* ##### **[点击这里直达下载领取链接](https://gitee.com/vip204888/android-p7)**