Android Jetpack之LiveData

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mingyunxiaohai/article/details/89429932

LiveData概述

LiveData是一个可观察的数据持有者类,和常规的observable不同,它是用来感知生命周期的,这意味着它遵守其他应用组件(activity、fragment、service等)的生命周期。这就确保它只会更新处于活动状态的组件。

如果一个类实现了android.arch.lifecycle.Observer,那么LiveData就认为这个类是STARTED或者RESUMED状态。LiveData只会通知活动的观察者更新信息,不处于活动状态的观察者不会受到信息。

我们可以注册一个observer和实现了LifecycleOwner的类一起使用(在Support Library 26.1.0 和以上的版本中,activity和fragment已经默认实现了LifecycleOwner接口)。当生命周期改变的时候,可以删除观察者,这对activity和fragment非常有用,它们可以安全的观察LiveData而不用担心内存泄露。当activity和fragment的生命周期执行到destroyed的时候立即取消订阅。

使用LiveData

  1. 创建一个LiveData用来保存特定的类型数据的实例,这通常在ViewModel中完成
  2. 创建一个Observer,定义onChanged()方法当数据改变的时候会执行这个方法,我们可以在activitt、fragment等UI控制器中创建这个Observer。
  3. 使用observe()方法把Observer添加到LiveData上。这个方法持有一个LifecycleOwner对象,一般在 activity 或 fragment中添加

可以通过observeForever(Observer)这个方法,注册一个永久的观察者,那么这个观察者就被认为是永远活动的,它也就一直能收到变化的通知,可以使用removeObserver(Observer)方法将它删除

LiveData是一个包装器,可以和任何对象使用。包括实现了Collections的对象,比如List,一个LiveData对象一般存在一个ViewModel中,通过一个getter方法获得。

示例

public class NameViewModel extends ViewModel {

private MutableLiveData<String> currentName;
    // 创建一个String类型的LiveData
    public MutableLiveData<String> getCurrentName() {
        if (currentName == null) {
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }

}

确保存在LiveData中的数据不是activity和fragment,原因是他们是用来显示数据的而不是保存数据的状态。并且把LiveData和activity和fragment分离,并允许LiveData对象在配置更改后继续存在

观察LiveData对象

多数情况下,我们在app组件的onCreate()方法中来观察LiveData对象。原因如下

  1. 确保activity和fragment不会再onResume()中进行冗余的调用
  2. 确保activity和fragment在变为活动状态的时候能立即收到并显示数据

LiveData一般情况下只在数据发生改变的时候才会通知在活动状态下的activity或者fragment更新,还有当观察者从非活动状态变为活动状态的时候也会改变。此外,如果观察者第二次从非活动状态更改为活动状态,则只有在自上次活动状态以来该值发生更改时才会收到更新。

更新LiveData对象

LiveData没有公开的方法来更新它存储的对象,它的子类MutableLiveData提供了setValue(T) 和postValue(T)两个方法来更新数据,setValue(T)是在主线程中更新数据,postValue(T)是在子线程中更新数据

例子:

public class NameViewModel1 extends ViewModel {

    private MutableLiveData<String> currentName;

    public MutableLiveData<String> getCurrentName() {
        if (currentName == null) {
            currentName = new MutableLiveData<String>();
            loadData();
        }
        return currentName;
    }

    private void loadData() {
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                currentName.postValue("Lily");
            }
        }, 1000);
    }

}

public class NameActivity extends AppCompatActivity {
    private NameViewModel1 mViewModel;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_name);

        final TextView textView = findViewById(R.id.tv_name);
        //// 获取ViewModel.
        mViewModel = ViewModelProviders.of(this).get(NameViewModel1.class);
        // 观察LiveData,传入当前的LifecycleOwner和观察者
        mViewModel.getCurrentName().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                textView.setText(s);
            }
        });
    }
}

上面例子中,ViewModel中模拟一秒钟之后改变MutableLiveData中的值,NameActivity中也会跟着改变。

使用LiveData的优点

  • 确保UI跟数据匹配,LiveData遵循观察者模式,可以在数据更改时更改UI
  • 没有内存泄漏,观察者绑定Lifecycle对象,会在其销毁的时候自行清理
  • 不会因为stopped activities而崩溃,如果观察者处于非活动状态,那么它是不会收到任何的LiveData的事件
  • 不用在手动处理生命周期,UI组件只观察相关的数据,不会停止或者恢复观察,LiveData会自动管理数据,它在观察UI组件的时候,可以感知到生命周期的变化。
  • 始终保持最新数据,后台activity返回前台时,可以立即接收到数据
  • 共享资源,我们可以扩展LiveData对象,使用单例模式包装系统服务,这样就可以在app中共享服务,只要LiveData 连接到系统服务,其他要使用系统服务的观察者只需观察这个LiveData对象即可。

扩展LiveData

直接看官网的例子,继承LiveData之后,重写其onActive()和onInactive()方法,在onActive()中注册一个监听,在onInactive()方法中取消这个监听。

public class StockLiveData extends LiveData<BigDecimal> {
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };

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

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
        stockManager.removeUpdates(listener);
    }
}
public class MyFragment extends Fragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        LiveData<BigDecimal> myPriceListener = ...;
        myPriceListener.observe(this, price -> {
            // Update the UI.
        });
    }
}
  • onActive(),当LiveData对象处于活动状态的时候会回调此方法
  • onInactive(),当LiveData对象没有活动的观察者的时候回调此方法,我们可以做一些清除操作
  • setValue(T),更新LiveData实例的值,并通知其他处于活动状态的观察者改变

LiveData可以感知生命周期,这意味着我们可以在多个activity、fragment、service中共享它
为了保持实例的一致性,可以把它设置成单例的

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

    @MainThread
    public static StockLiveData get(String symbol) {
        if (sInstance == null) {
            sInstance = new StockLiveData(symbol);
        }
        return sInstance;
    }

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

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
        stockManager.removeUpdates(listener);
    }
}
public class MyFragment extends Fragment {
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        StockLiveData.get(symbol).observe(this, price -> {
            // Update the UI.
        });
    }
}

多个activity和fragment都可以观察上面自定义LiveData的实例,LiveData只会更新当前处于活动状态的组件。

转换LiveData

在LiveData对象把更新的数据分发给观察者之前,我们可以通过转换操作,对数据进行加工。android.arch.lifecycle类中提供了转换的方法。

Transformations.map() 可转换LiveData的输出

上面NameActivity的例子中我们可以更改一下

      protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_name);

        final TextView textView = findViewById(R.id.tv_name);
        mViewModel = ViewModelProviders.of(this).get(NameViewModel1.class);

        LiveData<String> userNameMap = Transformations.map(mViewModel.getCurrentName(), new Function<String, String>() {
            @Override
            public String apply(String input) {
                return input + "哈哈哈";
            }
        });

        userNameMap.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                textView.setText(s);
            }
        });
    }

上面代码会在在name后面拼接一个哈哈哈,这只是最简单的逻辑,我们可以在map函数中添加更多的逻辑,比如我们的LiveData接收的是一个User对象,最后输出的是名字的字符串等

Transformations.switchMap() 更改被LiveData观察的对象

和map()方法类似,区别是switchMap()给出的是LiveData,而map给出的是具体值。

private LiveData<User> getUser(String id) {
  ...;
}

LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

比如上面的方法,通过switchMap,把用户的id和LiveData相关联,当用户的id发生改变的时候,会重新调用查找用户的方法,最后返新用户的LiveData的数据,这样不管查询多少个用户,界面都只需观察生成的LiveData一次

MediatorLiveData 提供自定义的转换

可以使用MediatorLiveData来自定义转换,该类监听其他LiveData对象并处理它们发出的事件。MediatorLiveData正确地将其状态传播到LiveData对象,更多参考Transformations

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

例如,如果LiveDataUI中有一个可以从本地数据库或网络更新的对象,则可以将以下源添加到该 MediatorLiveData对象:

  1. LiveData与存储在数据库中的数据关联的对象。
  2. LiveData与从网络访问的数据关联的对象。

LiveData源码:

上面的内容大部分都是官网的文档,通过看文档,知道了LiveData怎么用,下面来看看它的实现原理。

从注册开始(LiveData.observe()方法)

    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);
        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);
    }
  • 此方法传入的两个对象其实就是被观察者和观察者
  • 如果当前生命周期是销毁状态,直接返回
  • 把被观察者和观察者包装成一个LifecycleBoundObserver对象。
  • mObservers是一个链表,用来缓存包装对象,这里判断一下当前的包装对象是否已经存在了。
  • 最后把这个包装对象注册到生命周期组件(被观察者owner)中,addObserver方法在上一篇lifcycles中看过了。

上一篇Lifecyles中我们知道,当被观察者owner(fragment、activity等)生命周期变化的时候,会调用传入的观察者的onStateChanged方法。这里传入的是LifecycleBoundObserver,所以会调用LifecycleBoundObserver的onStateChanged方法,它里面又调用了我们传入的observer的onChanged方法,我们就能拿到数据了。

下面看看这个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(LifecycleOwner source, Lifecycle.Event event) {
            if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
                removeObserver(mObserver);
                return;
            }
            activeStateChanged(shouldBeActive());
        }

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

        @Override
        void detachObserver() {
            mOwner.getLifecycle().removeObserver(this);
        }
    }
    private abstract class ObserverWrapper {
        final Observer<? super T> mObserver;
        boolean mActive;
        int mLastVersion = START_VERSION;

        ObserverWrapper(Observer<? super T> observer) {
            mObserver = observer;
        }

        abstract boolean shouldBeActive();

        boolean isAttachedTo(LifecycleOwner owner) {
            return false;
        }

        void detachObserver() {
        }

        void activeStateChanged(boolean newActive) {
            if (newActive == mActive) {
                return;
            }
            // immediately set active state, so we'd never dispatch anything to inactive
            // owner
            mActive = newActive;
            boolean wasInactive = LiveData.this.mActiveCount == 0;
            LiveData.this.mActiveCount += mActive ? 1 : -1;
            if (wasInactive && mActive) {
                onActive();
            }
            if (LiveData.this.mActiveCount == 0 && !mActive) {
                onInactive();
            }
            if (mActive) {
                dispatchingValue(this);
            }
        }
    }
  • LifecycleBoundObserver继承自抽象类ObserverWrapper,实现了LifecycleEventObserver接口,LifecycleEventObserver中有个onStateChanged方法。当生命周期组件的生命周期发生变化的时候,就调用这个onStateChanged方法。
  • onStateChanged中,判断如果当前是销毁状态,移除当前观察者并返回,这里它自动移除了观察者,我们也就不用手动移除观察者了。如果不是调用父类ObserverWrapper中的activeStateChanged方法。
  • 前面看文档我们知道,LiveData只有在activiy或者fragment等生命周期组件处于前台的时候才会收到事件。就在activeStateChanged这个方法中判断了是不是活动状态
  • onActive();和 onInactive();这两个是空方法,前面文档中如果我们自定义一个LiveData,就会重写这两个方法。
  • 如果是活动状态,调用dispatchingValue方法分发事件,传入当前包装对象
    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;
    }
  • 如果正在分发着事件返回
  • 如果传入的包装对象为空,就去前面说的链表mObservers中遍历,如果找到了或者我们传入的不为空,就调用considerNotify方法通知观察者。
   private void considerNotify(ObserverWrapper observer) {
        if (!observer.mActive) {
            return;
        }
        if (!observer.shouldBeActive()) {
            observer.activeStateChanged(false);
            return;
        }
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        observer.mLastVersion = mVersion;
        //noinspection unchecked
        observer.mObserver.onChanged((T) mData);
    }

如果mLastVersion小于当前的mVersion值才会继续往下执行。mVersion在setValue方法中++的,调用一个setValue方法,mVersion就+1,所以,当生命周期发生了变化,即使我们调用了considerNotify方法,但是当前的值没有改变,也不会执行观察者的onChanged方法。

observer.mObserver就是我们最开始传入的观察者,调用它的onChanged方法传入data,我们在activity或者fragment中就能收到这个data值了。

mData的值是在setValue方法中被赋值的。LiveData中有两种赋值的方法:setValue方法。和postValue,一个是在主线程中赋值,一个是在子线程中赋值。postValue其实就是在一个Runnable中地哦啊用setValue方法。

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

Ok到这里源码就看完了。下面思考一下,前面文档中我们知道,如果一个activity或者fragment在后台,他是收不到数据更新的。当切换到前台拿上就能收到。怎么实现的呢?

前面activeStateChanged方法中我们知道,只有activity或者fragment是活动状态才能会调用 dispatchingValue方法,如果它们在后台,这时候不调用dispatchingValue方法。当它们切换回到前台的时候,生命周期发生改变,会调用LifecycleBoundObserver中的onStateChange方法,然后又会进入到activeStateChanged方法中,这时候状态是活动的就可以调用dispatchingValue方法分发了。

猜你喜欢

转载自blog.csdn.net/mingyunxiaohai/article/details/89429932