Android Jetpack之LiveData

Android Jetpack之LiveData

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方法获得。

示例

1
2
3
4
5
6
7
8
9
10
11
12
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)是在子线程中更新数据

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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()方法中取消这个监听。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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中共享它
为了保持实例的一致性,可以把它设置成单例的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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的例子中我们可以更改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  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给出的是具体值。

1
2
3
4
5
6
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()方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

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方法分发事件,传入当前包装对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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方法通知观察者。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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方法。

    1
    2
    3
    4
    5
    6
    protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
    }

可以看到没次setValue,mVersion都会加一,并且调用dispatchingValue方法进行消息分发。

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

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

コメント

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×