Skip to content

LiveData

LiveData 的概念比较简单,就是使你的数据 能够 具备生命周期的特性 举个例子:我们去本地数据库查询一个 ‘列表’,是不是先开一个异步线程,查询到 ‘列表’ 后在通过 Handler 从 异步线程中把 ‘列表’ push 到 UI 线程, 使用 LiveData 后:

  1. ROOM 框架 支持返回 LiveData<T> 格式的数据,
  2. 我们只需要在界面 使用 LiveData.observer.onChanged() 就好了
  3. 当我们列表有新增数据 还会自动 出发 observer.onChanged() 这样的的福利还不安利吗?
  1. Retrofit 同样也支持了 LiveData
  2. 配合 kotlin 协程使用效果更佳。
  3. 当然你最好结合 ViewModel+DataBinding 来实现你的懒人(MVVM)架构

具体例子

以 Google BaseSimple 为例,我迁移了一份到 gitee https://gitee.com/pengqinping/architecture-components-samples/tree/master/BasicSample 建议 在 AS 打开项目查看

  1. ProductDao 编写查询 并定义 searchAllProducts
  2. DataRepository 中调用 searchAllProducts (架构分层 不贴代码)
  3. ProductListViewModel 中调用 searchProducts (架构分层 不贴代码)
  4. ProductListFragment 中监听 LiveData

1.ROOM 返回 livedata

java
// ROOM 通过注解 在编译的时候会生成实现类 ProductDao_Impl
 @Query("SELECT products.* FROM products JOIN productsFts ON (products.id = productsFts.rowid) "
        + "WHERE productsFts MATCH :query")
    LiveData<List<ProductEntity>> searchAllProducts(String query);

ProductDao_Impl 目录结构, 感兴趣可以去看看具体实现, 这个文件是通过 annotationProcessor room.compiler 依赖在编译的时候通过注解形成。 ProductDao_Impl

2. ProductListFragment.java livedata 监听

java
// 只要数据变化 mbinding 会自动去刷新UI 不用我们在 setView setText 等待一些列操作
 private void subscribeUi(LiveData<List<ProductEntity>> liveData) {
    // Update the list when the data changes
    liveData.observe(getViewLifecycleOwner(), myProducts -> {
        // 更新UI操作
        if (myProducts != null) {
            mBinding.setIsLoading(false);
            mProductAdapter.setProductList(myProducts);
        } else {
            mBinding.setIsLoading(true);
        }
        // espresso does not know how to wait for data binding's loop so we execute changes
        // sync.
        mBinding.executePendingBindings();
    });
}

LiveData 源码浅析

我们从下面几个操作上来看 LiveData 的实现

  1. 我们创建普通的LiveData<T>一般是直接通过构造器来 创建对象
  2. 更新数据 livedata.setValue(T) liveData.postValue(T)
  3. observer LiveData 的变化

1. LiveData<T>()

java
 public LiveData(T value) {
    mData = value;
    mVersion = START_VERSION + 1;
}

2. setValue(T)

java
// 必须在主线程调用
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");
    mVersion++;
    mData = value;
    dispatchingValue(null);
}

3. postValue(T)

java
// 可以在子线程调用,这里有切换线程的操作
protected void postValue(T value) {
    boolean postTask;
    synchronized (mDataLock) {
        postTask = mPendingData == NOT_SET;
        mPendingData = value;
    }
    if (!postTask) {
        return;
    }
    // 切换线程 最终是 通过 DefaultTaskExecutor.postToMainThread() 这里面会创建一个 MainHandler 最终还是通过 handler 去实现的,
    ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
// 其实就做了一个同步锁,最终还是通过 setValue来更新,所以基本所有的 通知更新 都在 dispatchingValue() 里面
private final Runnable mPostValueRunnable = new Runnable() {
    @SuppressWarnings("unchecked")
    @Override
    public void run() {
        Object newValue;
        synchronized (mDataLock) {
            newValue = mPendingData;
            mPendingData = NOT_SET;
        }
        setValue((T) newValue);
    }
};

4. dispatchingValue(@Nullable ObserverWrapper initiator)

java
 void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            // 遍历 所有的 mObserver 去进行通知
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

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;
    // 发布通知
    observer.mObserver.onChanged((T) mData);
}

mObservers 是在 去监听 LiveData 的时候传入的 liveData.observe(getViewLifecycleOwner(),Observer{})

java
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {
        // ignore
        return;
    }
    // lifecycle相关的逻辑也只在这里实现的
    // owner 一般是 Activity 和 Fragment (最好是 androidx包下的)
    //
    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);
}

源码分析到此结束,感兴趣可自行查看更多细节

java
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
        @NonNull Lifecycle.Event event) {
   // 当 Activity 或者 fragment destory 后 移除出掉 observer 所以不会出现 destory 后 liveData 在收到消息的情况
    if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
        removeObserver(mObserver);
        return;
    }
    activeStateChanged(shouldBeActive());
}

Transformations.map() 和 Transformations.switchMap()

  • 为什么需要Trasnformations
  • 如果你的界面需要显示一个 String 接口给你了一个 List<String>,你可能会想,我把 List<String> 传过去自己 截取拼接。这样虽然也可以,但是,你凭借出来的数据 不是LiveData类型的。没法 Observers. 这个时候你就需要 Trasnformations

Document: 中文版的我硬是没有看懂 You may want to make changes to the value stored in a LiveData object before dispatching it to the observers, or you may need to return a different LiveData instance based on the value of another one. The Lifecycle package provides the Transformations class which includes helper methods that support these scenarios.

1. Transformations.map()

  • 文档说的第一种情况就是 我想要展示 UserName, 实例中的都是 LiveData 不可变,也就是初始化后不能改变它的值
kotlin
val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<String> = Transformations.map(userLiveData) {
    user -> "${user.name} ${user.lastName}"
}

2. Trasnformations.switchMap()

比如根据一个 Id 去查询一个列表,如果直接使用函数,并不能体现出 LiveData 的特性,这个时候想直接把查询结果作为 LiveData 的时候我们就需要 LiveData 了

kotlin
private fun getUser(id: String): LiveData<User> {
  ...
  //  这里的请求可以是 retrofit 也可以是 ROOM  目前这两个都支持了直接返回LiveData
}
val userId: LiveData<String> = ...
val user = Transformations.switchMap(userId) { id -> getUser(id) }

下面的例子中 我改变 liveGroupId 数据,links 会自动的去更新

kotlin
// ViewModel
private val liveGroupId = MutableLiveData<Long>()
val links = Transformations.switchMap(liveGroupId) {
    linkRepository.findLinksWithGroupId(it)
}
// Fragment
linkViewModel.links.observe(this, Observer {
            if (it.isNullOrEmpty()) {
                enableDeleteMenu()
                state_view.showEmptyView()
            } else {
                state_view.showContent()
            }
            // 为空也要去清理下 Adapter 否则还有数据
            linkAdapter.setNewData(it)
        })