LiveData详解

1.LiveData介绍

LiveData是Jetpack AAC的重要组件,同时已有一个同名抽象类。
LiveData,原意是活着的数据。数据还能有生命?先来看下官方的定义:

LiveData是一种可观察的数据存储器类。它与常规的可观察类不同,LiveData具有生命周期感知能力,意指它遵循其他应用组件(如Activity/Fragment)的生命周期。这种感知能力可确保LiveData仅更新处于活跃生命周期状态的应用组件观察者。

拆解开来:
1.LiveData是一个数据持有者,给源数据包装一层。
2.源数据使用LiveData包装后,可以被observer观察,数据有更新时observer可感知。
3.但observer的感知,只发生在(Activity/Fragment)活跃生命周期状态(STARTED,RESUMED)。

也就是说,LiveData使得数据的更新能以观察者模式被observer感知,且此感知只发生在LifecycleOwner的活跃生命周期状态。

2.特点

使用 LiveData 具有以下优势:

  • 确保界面符合数据状态,当生命周期状态变化时,LiveData通知Observer,可以在observer中更新界面。观察者可以在生命周期状态更改时刷新界面,而不是在每次数据变化时刷新界面。
  • 不会发生内存泄漏,observer会在LifecycleOwner状态变为DESTROYED后自动remove。
  • 不会因 Activity 停止而导致崩溃,如果LifecycleOwner生命周期处于非活跃状态,则它不会接收任何 LiveData事件。
  • 不需要手动解除观察,开发者不需要在onPause或onDestroy方法中解除对LiveData的观察,因为LiveData能感知生命周期状态变化,所以会自动管理所有这些操作。
  • 数据始终保持最新状态,数据更新时 若LifecycleOwner为非活跃状态,那么会在变为活跃时接收最新数据。例如,曾经在后台的 Activity 会在返回前台后,observer立即接收最新的数据。

3.LiveData的使用

1.创建LiveData实例,指定源数据类型
2.创建Observer实例,实现onChanged()方法,用于接收源数据变化并刷新UI
3.LiveData实例使用observe()方法添加观察者,并传入LifecycleOwner
4.LiveData实例使用setValue()/postValue()更新源数据 (子线程要postValue())

举个列子:

public class LiveDataTestActivity extends AppCompatActivity{

   private MutableLiveData<String> mLiveData;
   
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_lifecycle_test);
       
       //liveData基本使用
       mLiveData = new MutableLiveData<>();
       mLiveData.observe(this, new Observer<String>() {
           @Override
           public void onChanged(String s) {
               Log.i(TAG, "onChanged: "+s);
           }
       });
       Log.i(TAG, "onCreate: ");
       mLiveData.setValue("onCreate");//activity是非活跃状态,不会回调onChanged。变为活跃时,value被onStart中的value覆盖
   }
   @Override
   protected void onStart() {
       super.onStart();
       Log.i(TAG, "onStart: ");
       mLiveData.setValue("onStart");//活跃状态,会回调onChanged。并且value会覆盖onCreate、onStop中设置的value
   }
   @Override
   protected void onResume() {
       super.onResume();
       Log.i(TAG, "onResume: ");
       mLiveData.setValue("onResume");//活跃状态,回调onChanged
   }
   @Override
   protected void onPause() {
       super.onPause();
       Log.i(TAG, "onPause: ");
       mLiveData.setValue("onPause");//活跃状态,回调onChanged
   }
   @Override
   protected void onStop() {
       super.onStop();
       Log.i(TAG, "onStop: ");
       mLiveData.setValue("onStop");//非活跃状态,不会回调onChanged。后面变为活跃时,value被onStart中的value覆盖
   }
   @Override
   protected void onDestroy() {
       super.onDestroy();
       Log.i(TAG, "onDestroy: ");
       mLiveData.setValue("onDestroy");//非活跃状态,且此时Observer已被移除,不会回调onChanged
   }
}

结果如下:

  • 首先打开页面,onCreate()中setValue,由于activity是非活跃状态,不会立即回调onChanged。当走到onStart()变为活跃时,onChanged被调用,但value被onStart()中setValue的value覆盖,所以打印的是onChanged: onStart。(为啥不是连续打印两次呢?,是因为ON_START事件是在onStart() return之后,即onStart()走完之后才变为活跃<详见上一篇>,此时observer接收最新的数据。) 接着走到onResume(),也setValue了,同样是活跃状态,所以立刻回调onChanged,打印onChanged: onResume

  • 按Home键时,onPause()中setValue,活跃状态,立刻回调onChanged方法。onStop()执行时已经变为非活跃状态,此时setValue不会立即回调onChanged方法。

  • 再点开时,走到onStart()变为活跃时,onChanged被调用,但value被onStart()中setValue的value覆盖,所以打印的是onChanged: onStart。接着走到onResume(),也setValue了,同样是活跃状态,所以立刻回调onChanged。

  • 返回键退出时,onPause()/onStop()的效果和按Home键一样。onDestroy()中setValue,此时非活跃状态,且此时observer已被移除,不会回调onChanged。

另外,除了使用observe()方法添加观察者,也可以使用observeForever(Observer)方法来注册未关联 LifecycleOwner的观察者。在这种情况下,观察者会被视为始终处于活跃状态。

4.扩展使用

扩展包括两点:
1.自定义LiveData,本身回调方法的覆写:onActive(),onInactive().
2.使用LiveData为单列模式,便于在多个Activity,Fragment之间共享数据。

官方的例子如下:

public class StockLiveData extends LiveData<BigDecimal> {
        private static StockLiveData sInstance; //单实例
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);//监听到股价变化 使用setValue(price) 告知所有活跃观察者
            }
        };

    //获取单例
        @MainThread
        public static StockLiveData get(String symbol) {
            if (sInstance == null) {
                sInstance = new StockLiveData(symbol);
            }
            return sInstance;
        }

        private StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        //活跃的观察者(LifecycleOwner)数量从 0 变为 1 时调用
        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);//开始观察股价更新
        }

        //活跃的观察者(LifecycleOwner)数量从 1 变为 0 时调用。这不代表没有观察者了,可能是全都不活跃了。可以使用hasObservers()检查是否有观察者。
        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);//移除股价更新的观察
        }
    }

为了观察股票价格变动,继承LiveData自定义了StockLiveData,且为单例模式,只能通过get(String symbol)方法获取实例。 并且重写了onActive()、onInactive(),并加入了 开始观察股价更新、移除股价更新观察 的逻辑。

  • onActive()调用时机为:活跃的观察者(LifecycleOwner)数量从 0 变为 1 时。
  • onInactive()调用时机为:活跃的观察者(LifecycleOwner)数量从 1 变为 0 时。
    也就是说,只有当 存在活跃的观察者(LifecycleOwner)时 才会连接到 股价更新服务 监听股价变化。使用如下:
 public class MyFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            //获取StockLiveData单实例,添加观察者,更新UI
            StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
                // Update the UI.
            });
        }
    }

由于StockLiveData是单实例模式,那么多个LifycycleOwner(Activity、Fragment)间就可以共享数据了。

5.高级用法

如果希望在将 LiveData 对象分派给观察者之前对存储在其中的值进行更改,或者需要根据另一个实例的值返回不同的 LiveData 实例,可以使用LiveData中提供的Transformations类。

5.1 数据修改-Transformations.map

        //Integer类型的liveData1
        MutableLiveData<Integer> liveData1 = new MutableLiveData<>();
        //转换成String类型的liveDataMap
        LiveData<String> liveDataMap = Transformations.map(liveData1, new Function<Integer, String>() {
            @Override
            public String apply(Integer input) {
                String s = input + " + Transformations.map";
                Log.i(TAG, "apply: " + s);
                return s;
            }
        });
        liveDataMap.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged1: "+s);
            }
        });

        liveData1.setValue(100);

使用很简单:原本的liveData1 没有添加观察者,而是使用Transformations.map()方法 对liveData1的数据进行的修改 生成了新的liveDataMap,liveDataMap添加观察者,最后liveData1设置数据 。

5.2 数据切换-Transformations.switchMap

如果想要根据某个值 切换观察不同LiveData数据,则可以使用Transformations.switchMap()方法。

//两个liveData,由liveDataSwitch决定 返回哪个livaData数据
        MutableLiveData<String> liveData3 = new MutableLiveData<>();
        MutableLiveData<String> liveData4 = new MutableLiveData<>();
        
    //切换条件LiveData,liveDataSwitch的value 是切换条件
        MutableLiveData<Boolean> liveDataSwitch = new MutableLiveData<>();
        
    //liveDataSwitchMap由switchMap()方法生成,用于添加观察者
        LiveData<String> liveDataSwitchMap = Transformations.switchMap(liveDataSwitch, new Function<Boolean, LiveData<String>>() {
            @Override
            public LiveData<String> apply(Boolean input) {
            //这里是具体切换逻辑:根据liveDataSwitch的value返回哪个liveData
                if (input) {
                    return liveData3;
                }
                return liveData4;
            }
        });

        liveDataSwitchMap.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged2: " + s);
            }
        });

        boolean switchValue = true;
        liveDataSwitch.setValue(switchValue);//设置切换条件值

        liveData3.setValue("liveData3");
        liveData4.setValue("liveData4");

liveData3、liveData4是两个数据源,有一个判断条件来决定 取哪一个数据 ,这个条件就是liveDataSwitch,如果值为true则取liveData3,false则取liveData4。 Transformations.switchMap()就用于实现这一逻辑,返回值liveDataSwitchMap添加观察者就可以了

5.3 观察多个数据-MediatorLiveData

MediatorLiveData 是 LiveData 的子类,允许合并多个 LiveData 源。只要任何原始的 LiveData 源对象发生更改,就会触发 MediatorLiveData 对象的观察者。

        MediatorLiveData<String> mediatorLiveData = new MediatorLiveData<>();

        MutableLiveData<String> liveData5 = new MutableLiveData<>();
        MutableLiveData<String> liveData6 = new MutableLiveData<>();

    //添加 源 LiveData
        mediatorLiveData.addSource(liveData5, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged3: " + s);
                mediatorLiveData.setValue(s);
            }
        });
    //添加 源 LiveData
        mediatorLiveData.addSource(liveData6, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged4: " + s);
                mediatorLiveData.setValue(s);
            }
        });

    //添加观察
        mediatorLiveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.i(TAG, "onChanged5: "+s);
                //无论liveData5、liveData6更新,都可以接收到
            }
        });
        
        liveData5.setValue("liveData5");
        //liveData6.setValue("liveData6");

例如,如果界面中有可以从本地数据库或网络更新的 LiveData 对象,则可以向 MediatorLiveData 对象添加以下源:

  • 与存储在本地数据库中的数据关联的 liveData5
  • 与从网络访问的数据关联的 liveData6
    Activity 只需观察 MediatorLiveData 对象即可从这两个源接收更新。

6.源码分析

前面提到LiveData几个特点,能感知生命周期状态变化,不用手动解除观察等等,这些是如何做到的呢?

6.1添加观察者

LiveData原理是观察者模式,下面先从LiveData.observer()方法看起:

    /**
     * 添加观察者. 事件在主线程分发. 如果LiveData已经有数据,将直接分发给observer。
     * 观察者只在LifecycleOwner活跃时接受事件,如果变为DESTROYED状态,observer自动移除。
     * 当数据在非活跃时更新,observer不会接收到。变为活跃时 将自动接收前面最新的数据。 
     * LifecycleOwner非DESTROYED状态时,LiveData持有observer和 owner的强引用,DESTROYED状态时自动移除引用。
     * @param owner    控制observer的LifecycleOwner
     * @param observer 接收事件的observer
     */
    @MainThread
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        assertMainThread("observe");
        if (owner.getLifecycle().getCurrentState() == DESTROYED) {
            // LifecycleOwner是DESTROYED状态,直接忽略
            return;
        }
        //使用LifecycleOwner、observer 组装成LifecycleBoundObserver,添加到mObservers中
        LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
        ObserverWrapper existing = mObservers中.putIfAbsent(observer, wrapper);
        if (existing != null && !existing.isAttachedTo(owner)) {
        //!existing.isAttachedTo(owner)说明已经添加到mObservers中的observer指定的owner不是传进来的owner,就会报错“不能添加同一个observer却不同LifecycleOwner”
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;//这里说明已经添加到mObservers中,且owner就是传进来的owner
        }
        owner.getLifecycle().addObserver(wrapper);
    }

首先是判断LifecycleOwner是DESTROYED状态,就直接忽略,不能添加。接着使用LifecycleOwner、observer 组装成LifecycleBoundObserver包装实例wrapper,使用putIfAbsent方法observer-wrapper作为key-value添加到观察者列表mObservers中。(putIfAbsent意思是只有列表中没有这个observer时才会添加。)

然后对添加的结果进行判断,如果mObservers中已经存在此observer key,但value中的owner不是传进来的owner,就会报错“不能添加同一个observer却是不同LifecycleOwner”。如果是相同的owner,就直接returne。

最后用LifecycleOwner的Lifecycle添加observer的封装wrapper。

另外,再看observeForever方法:

 @MainThread
    public void observeForever(@NonNull Observer<? super T> observer) {
        assertMainThread("observeForever");
        AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
        ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
        if (existing instanceof LiveData.LifecycleBoundObserver) {
            throw new IllegalArgumentException("Cannot add the same observer"
                    + " with different lifecycles");
        }
        if (existing != null) {
            return;
        }
        wrapper.activeStateChanged(true);
    }

和observe()类似,只不过 会认为观察者一直是活跃状态,且不会自动移除观察者。

6.2 事件回调

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() { //至少是STARTED状态
            return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
        }

        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);//LifecycleOwner变成DESTROYED状态,则移除观察者
                return;
            }
            activeStateChanged(shouldBeActive());
        }

        @Override
        boolean isAttachedTo(LifecycleOwner owner) {
            return mOwner == owner;
        }

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }

LifecycleBoundObserver是LiveData的内部类,是对原始Observer的包装,把LifecycleOwner和Observer绑定在一起。当LifecycleOwner处于活跃状态,就称 LifecycleBoundObserver是活跃的观察者。

它实现自接口LifecycleEventObserver,实现了onStateChanged方法。

在LifecycleOwner生命周期状态变化时 判断如果是DESTROYED状态,则移除观察者。LiveData自动移除观察者特点就来源于此。 如果不是DESTROYED状态,将调用父类ObserverWrapper的activeStateChanged()方法处理 这个生命周期状态变化,shouldBeActive()的值作为参数,至少是STARTED状态为true,即活跃状态为true。

 private abstract class ObserverWrapper {
        ...
        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;//活跃状态 未发生变化时,不会处理。
            }
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;//没有活跃的观察者
            LiveData.this.mActiveCount += mActive ? 1 : -1;//mActive为true表示变为活跃
            if (wasInactive && mActive) {
                onActive();//活跃的观察者数量 由0变为1
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive(); //活跃的观察者数量 由1变为0
            }
            if (mActive) {
                dispatchingValue(this);//观察者变为活跃,就进行数据分发
            }
        }
    }

ObserverWrapper也是LiveData的内部类。mActive是ObserverWrapper的属性,表示此观察者是否活跃。如果活跃状态 未发生变化时,不会处理。

LiveData.this.mActiveCount == 0 是指 LiveData 的活跃观察者数量。活跃的观察者数量 由0变为1、由1变为0 会分别调用LiveData的 onActive()、onInactive()方法。这就是前面提到的扩展使用的回调方法。

最后观察者变为活跃,就使用LiveData的dispatchingValue(observerWrapper)进行数据分发:

void dispatchingValue(@Nullable ObserverWrapper initiator) {
        if (mDispatchingValue) {
            mDispatchInvalidated = true;//如果当前正在分发,则分发无效,return
            return;
        }
        mDispatchingValue = true; //标记正在分发
        do {
            mDispatchInvalidated = false; 
            if (initiator != null) {
                considerNotify(initiator); //observerWrapper不为空,使用considerNotify()通知真正的观察者
                initiator = null;
            } else { //observerWrapper为空,遍历通知所有的观察者
                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                        mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                    considerNotify(iterator.next().getValue());
                    if (mDispatchInvalidated) {
                        break;
                    }
                }
            }
        } while (mDispatchInvalidated);
        mDispatchingValue = false; 
    }

如果当前正在分发,则分发无效;observerWrapper不为空,就使用considerNotify()通知真正的观察者,observerWrapper为空 则遍历通知所有的观察者。 observerWrapper啥时候为空呢?这里先留个疑问。 继续看considerNotify()方法:

private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return; //观察者非活跃 return
        }
        //若当前observer对应owner非活跃,就会再调用activeStateChanged方法,并传入false,其内部会再次判断
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);//回调真正的mObserver的onChanged方法
    }

先进行状态检查:观察者是非活跃就return;若当前observer对应的owner非活跃,就会再调用activeStateChanged方法,并传入false,其内部会再次判断。最后回调真正的mObserver的onChanged方法,值是LivaData的变量mData。

到这里回调逻辑也通了。

数据更新

LivaData数据更新可以使用setValue(value)、postValue(value),区别在于postValue(value)用于 子线程:

//LivaData.java
    private final Runnable mPostValueRunnable = new Runnable() {
        @SuppressWarnings("unchecked")
        @Override
        public void run() {
            Object newValue;
            synchronized (mDataLock) {
                newValue = mPendingData;
                mPendingData = NOT_SET;
            }
            setValue((T) newValue); //也是走到setValue方法
        }
    };

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

postValue方法把Runable对象mPostValueRunnable抛到主线程,其run方法中还是使用的setValue(),继续看:

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

setValue()把value赋值给mData,然后调用dispatchingValue(null),参数是null,对应前面提到的observerWrapper为空的场景,即 遍历所有观察者 进行分发回调。

到这里观察者模式完整的实现逻辑就梳理清晰了:LivaData通过observe()添加 与LifecycleOwner绑定的观察者;观察者变为活跃时回调最新的数据;使用setValue()、postValue()更新数据时会通知回调所有的观察者。

7 LiveData当做事件传递碰到的那些坑

7.1 postValue数据丢失的问题

通过上面的源码分析:postValue 只是把传进来的数据先存到 mPendingData,然后往主线程抛一个 Runnable,在这个 Runnable 里面再调用 setValue 来把存起来的值真正设置上去,并回调观察者们。而如果在这个 Runnable 执行前多次 postValue,其实只是改变暂存的值 mPendingData,并不会再次抛另一个 Runnable。这就会出现后设置的值把前面的值覆盖掉的问题,会导致事件丢失

protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        // 这里先把数据暂存起来,后来的数据会覆盖前面的
        mPendingData = value;
    }
    // 这里保证只抛一个 mPostValueRunnable,#-.-
    if (!postTask) {
        return;
    }
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}

7.2 setValue不回调观察者

LiveData 的生命周期感知能力就体现在这里,它不会回调处于「非激活状态」(即 onStart 之后到 onPause 之前)的观察者,因为这时更新 View 没有意义,而且比较危险,它会等到观察者激活之后再把新的值回调给他。
但是如果我传了多个数据(假设都是用 setValue 保证不会被覆盖),那些处于非激活状态的观察者是毫不知情的,他们在激活的时候只会收到最后一个数据。这对于事件传递来说,就表现为事件丢失,中间传的任何数据都无法收到,那也就失去了事件传递的意义。

// LiveData 通知观察者时调的函数
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.
    if (!observer.shouldBeActive()) {
        observer.activeStateChanged(false);
        return;
    }
    // 每次更新数据都会版本加一,这里保证不会回调之前发送过的数据
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    //noinspection unchecked
    observer.mObserver.onChanged((T) mData);
}

8 如何解决?

8.1 打造一个不会丢失事件的LiveData

LiveData的其他功能做的很完善,只是会丢事件,我们要改造就要针对上面的问题逐个击破。

8.2 postValue问题

对于postValue的问题,既然它最后也是调动了setValue,丢数据是因为只抛了一次Runable,那我们就自己每次都往主线程抛一个Runable就能解决这个问题。

public class LiveDataUtils {
    private static Handler sMainHandler;
    /**
     * 用 setValue 更新 MutableLiveData 的数据,如果在子线程,就切换到主线程
     */
    public static <T> void setValue(MutableLiveData<T> mld, T d) {
        if (mld == null) {
            return;
        }
        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
            mld.setValue(d);
        } else {
            postSetValue(mld, d);
        }
    }

    /**
     * 向主线程的 handler 抛 SetValueRunnable
     */
    public static <T> void postSetValue(MutableLiveData<T> mld, T d) {
        if (sMainHandler == null) {
            sMainHandler = new Handler(Looper.getMainLooper());
        }
        sMainHandler.post(SetValueRunnable.create(mld, d));
    }

    private static class SetValueRunnable<T> implements Runnable {
        private final MutableLiveData<T> liveData;
        private final T data;

        private SetValueRunnable(@NonNull MutableLiveData<T> liveData, T data) {
            this.liveData = liveData;
            this.data = data;
        }

        @Override
        public void run() {
            liveData.setValue(data);
        }

        private static <T> SetValueRunnable<T> create(@NonNull MutableLiveData<T> liveData, T data) {
            return new SetValueRunnable<>(liveData, data);
        }
    }
}

8.3 打造一个生命周期感知的还不丢事件的观察者

/**
 * LiveData 用作事件传递时的观察者
 * 保证所有事件不丢失,保存非激活状态的事件,并能够在激活状态回调,且没有内存泄漏
 */
public class LiveEventObserver<T> implements LifecycleObserver, Observer<T> {
    private LiveData<T> mLiveData;
    private LifecycleOwner mOwner;
    private Observer<? super T> mObserver;

    private final List<T> mPendingData = new ArrayList<>();

    public LiveEventObserver(LiveData<T> liveData, LifecycleOwner owner, Observer<? super T> observer) {
        mLiveData = liveData;
        mOwner = owner;
        mObserver = observer;
        mOwner.getLifecycle().addObserver(this);
        mLiveData.observeForever(this);
    }

    /**
     * 在生命周期结束前的任何时候都可能会调用
     */
    @Override
    public void onChanged(@Nullable T t) {
        if (isActive()) {
            // 如果是激活状态,就直接更新
            mObserver.onChanged(t);
        } else {
            // 非激活状态先把数据存起来
            mPendingData.add(t);
        }
    }

    /**
     * @return 是否是激活状态,即 onStart 之后到 onPause 之前
     */
    private boolean isActive() {
        return mOwner.getLifecycle().getCurrentState()
                .isAtLeast(Lifecycle.State.STARTED);
    }

    /**
     * onStart 之后就是激活状态了,如果之前存的有数据,就发送出去
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    private void onEvent(LifecycleOwner owner, Lifecycle.Event event) {
        if (owner != mOwner) {
            return;
        }
        if (event == Lifecycle.Event.ON_START || event == Lifecycle.Event.ON_RESUME) {
            for (int i = 0; i < mPendingData.size(); i++) {
                mObserver.onChanged(mPendingData.get(i));
            }
            mPendingData.clear();
        }
    }

    /**
     * onDestroy 时解除各方的观察和绑定,并清空数据
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    private void onDestroy() {
        mLiveData.removeObserver(this);
        mLiveData = null;

        mOwner.getLifecycle().removeObserver(this);
        mOwner = null;

        mPendingData.clear();

        mObserver = null;
    }


    public static <T> void bind(@NonNull LiveData<T> liveData,
                                @NonNull LifecycleOwner owner,
                                @NonNull Observer<? super T> observer) {
        if (owner.getLifecycle().getCurrentState() == Lifecycle.State.DESTROYED) {
            return;
        }
        new LiveEventObserver<>(liveData, owner, observer);
    }
}

使用如下:

/**
 * 用作事件总线的 {@link MutableLiveData}
 */
public class EventMutableLiveData<T> extends MutableLiveData<T> {
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        LiveEventObserver.bind(this, owner, observer);
    }

    @Override
    public void postValue(T value) {
        LiveDataUtils.setValue(this, value);
    }
}

/**
 * 用作事件总线的 {@link MediatorLiveData}
 */
public class EventMediatorLiveData<T> extends MediatorLiveData<T> {
    @Override
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
        LiveEventObserver.bind(this, owner, observer);
    }

    @Override
    public void postValue(T value) {
        LiveDataUtils.setValue(this, value);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容