Android Jetpack ------ LiveData的使用

Posted 切切歆语

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Jetpack ------ LiveData的使用相关的知识,希望对你有一定的参考价值。

LiveData介绍

LivaData是一个可被观察的数据容器类。具体来说,可以将LiveData理解为一个数据的容器,它将数据包装起来,使数据成为观察者,当该数据发生变化时,观察者能够获得通知。与常规的可观察类不同,LiveData可以感知(如Activity、Fragment或Service)的生命周期。

简单来说,LiveData具有如下优势

  1.     LiveData 遵循观察者模式。当生命周期状态发生变化时,LiveData 会通知 Observer 对象,可以在这些Observer对象中更新界面
  2.     不会发送内存泄露
  3.     如果观察者的生周期处于非活跃状态(如返回栈中的Activity),则它不会接收任何LivaData事件,但是,当非活跃状态变成活跃状态时会立刻接收最新的数据(后台的Activity返回前台时)
  4.     当config导致Activity/Fragment重建时,不需要再手动的管理数据的存储与恢复。

LiveData和ViewModel的关系

进一步区别一下ViewModel和LiveData。ViewModel用于存放页面所需的各种数据,它还包括一些业务逻辑等,比如我们可以在ViewModel对数据进行加工,获取等操作。而对页面来说,它并不关心这些业务逻辑,它只关心需要展示的数据是什么,并且希望在数据发生变化时,能及时得到通知并做出更新。LiveData的作用就是,在ViewModel中的数据发生变化时通知页面。从LiveData(实时数据)这个名字,我们也能推测出,它的特性与作用。

我们来看看,如何在ViewModel中使用LiveData对数据进行包装。LiveData是一个抽象类,不能直接使用,所以通常我们使用它的直接子类MutableLiveData。

public class TimerWithLiveDataViewModel extends ViewModel
{
    //将“秒钟”这个字段用MutableLiveData包装起来
    private MutableLiveData<Integer> currentSecond;

    public LiveData<Integer> getCurrentSecond()
    {
        if (currentSecond == null)
        {
            currentSecond = new MutableLiveData<>();
        }
        return currentSecond;
    }
}

LiveData定义之后,如何利用它实现页面与ViewModel之间的通信呢?

public class LiveDataActivity extends AppCompatActivity {

    Button button;
    @Override
    protected void onCreate(@Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.viewmodel);

        button = findViewById(R.id.btn1);
        button.setVisibility(View.VISIBLE);



        initComp();
    }

    private void initComp(){
        final TextView textView = findViewById(R.id.text);
        //通过ViewModelProvider得到ViewModel
        TimerLiveDataViewModel timerViewModel = new ViewModelProvider(this).get(TimerLiveDataViewModel.class);

        //得到ViewModel中的LiveData
        final MutableLiveData<Integer> liveData = (MutableLiveData<Integer>) timerViewModel.getCurrentSecond();

        //通过liveData.observer()观察ViewModel中数据的变化
        liveData.observe(this, new Observer<Integer>() {
            @Override
            public void onChanged(Integer integer) {
                textView.setText("更新时间:"+integer);
            }
        });

        timerViewModel.startTiming();

        //重置计时器
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //通过LiveData.setValue()/LiveData.postValue(),完成对ViewModel中数据的更新
                liveData.setValue(0);
            }
        });
    }
}


在页面中,我们通过LiveData.observe()方法对LiveData包装的数据进行观察,反过来,当我们想要修改LiveData包装的数据时,可通过LiveData.postValue()/LiveData.setValue()来完成。postValue()是在非UI线程中使用,如果在UI线程中,则使用setValue()方法。

让我们深入LiveData.observe()方法的源码。

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
    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);
}

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

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


LifecycleBoundObserver 源码

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

当调用 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方法

 @MainThread
    protected void setValue(T value) {
        assertMainThread("setValue");
        mVersion++;
        mData = value;
        dispatchingValue(null);
    }

setValue()中,首先 断言是主线程,这里的关键是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;
    }

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

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

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





postValue方法

 protected void postValue(T value) {
        boolean postTask;
        synchronized (mDataLock) {
            postTask = mPendingData == NOT_SET;
            mPendingData = value;
        }
        if (!postTask) {
            return;
        }
        ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
    }

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

private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue);
        }
    };

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

LiveData.observeForever()方法

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

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


 

以上是关于Android Jetpack ------ LiveData的使用的主要内容,如果未能解决你的问题,请参考以下文章

Android Jetpack学习之旅--> 开始使用 Jetpack

Android Jetpack架构组件带你了解Android Jetpack

Android Jetpack简介

Jetpack系列 — LiveData

Android Jetpack架构组件——什么是Jetpack?

Android Jetpack架构组件——什么是Jetpack?