将项目添加到LiveData列表时通知观察者

问题描述 投票:19回答:5

将项目添加到LiveData列表时,我需要获取Observer事件。但据我所知,只有当我用新的列表替换旧列表时才会收到事件。例如,当我做下一个时:

list.value = mutableListOf(IssuePost(UserEntity(name, email, photoUrl), issueEntity))

观察者得到事件。但是当我只是将item添加到value时,Observer是静默的。您能否就我如何实施我的需求提出建议?

android kotlin android-livedata
5个回答
27
投票

在内部,LiveData将每个更改跟踪为版本号(简单计数器存储为int)。调用setValue()会增加此版本并使用新数据更新任何观察者(仅当观察者的版本号小于LiveData的版本时)。

看来启动此过程的唯一方法是调用setValue()或postValue()。副作用是如果LiveData的底层数据结构发生了变化(例如向Collection添加元素),则不会发生任何事情将其传达给观察者。

因此,在将项添加到列表后,您必须调用setValue()。我提供了两种方法可以在下面解决这个问题。

选项1

将列表保留在LiveData之外,并在列表内容更改时随参考更新。

private val mIssuePosts = ArrayList<IssuePost>()
private val mIssuePostLiveData = MutableLiveData<List<IssuePost>>()

fun addIssuePost(issuePost: IssuePost) {
   mIssuePosts.add(issuePost)
   mIssuePostLiveData.value = mIssuePosts
}

选项2

通过LiveData跟踪列表,并在列表内容更改时使用自己的值更新LiveData。

private val mIssuePostLiveData = MutableLiveData<List<IssuePost>>()

init {
   mIssuePostLiveData.value = ArrayList()
}

fun addIssuePost(issuePost: IssuePost) {
    mIssuePostLiveData.value?.add(issuePost)
    mIssuePostLiveData.value = mIssuePostLiveData.value
}

这些解决方案中的任何一个都应该帮助您每次修改当前列表时都必须创建一个新列表,以通知观察者。

更新:

我一直在使用类似的技术,因为Gnzlt在他的回答中提到使用Kotlin扩展函数将LiveData分配给自己以简化代码。这基本上是选项2自动:)我建议这样做。


16
投票

我使用Kotlin Extension Function使其更容易:

fun <T> MutableLiveData<T>.notifyObserver() {
    this.value = this.value
}

然后在任何MutableLiveData中使用它,如下所示:

fun addIssuePost(issuePost: IssuePost) {
    mIssuePostLiveData.value?.add(issuePost)
    mIssuePostLiveData.notifyObserver()
}

2
投票

这个怎么样?

public class ListLiveData<T> extends LiveData<List<T>> {
    public void addAll(List<T> items) {
        if (getValue() != null && items != null) {
            getValue().addAll(items);
            setValue(getValue());
        }
    }

    public void clear() {
        if (getValue() != null) {
            getValue().clear();
            setValue(getValue());
        }
    }

    @Override public void setValue(List<T> value) {
        super.setValue(value);
    }

    @Nullable @Override public List<T> getValue() {
        return super.getValue();
    }
}

// add changed listener
    mMessageList.observe(mActivity, new Observer() {
        @Override public void onChanged(@Nullable Object o) {
            notifyDataSetChanged();
        }
    });

0
投票

灵感来自@ user3682351这是我的解决方案。似乎我们无法单独更新LiveData值的属性,因此必须在每次操作时更新该值。这实际上是一个关于实时数据的小包装器,其中包含用于修改HashMap属性的便捷方法

import androidx.lifecycle.LiveData

/**
 * Hash Map Live Data
 *
 * Some convenience methods around live data for HashMaps. Putting a value on this will also update the entire live data
 * as well
 */
class HashMapLiveData<K, V> : LiveData<HashMap<K, V>>() {

    /**
     * Put a new value into this HashMap and update the value of this live data
     * @param k the key
     * @param v the value
     */
    fun put(k: K, v: V) {
        val oldData = value
        value = if (oldData == null) {
            hashMapOf(k to v)
        } else {
            oldData.put(k, v)
            oldData
        }
    }

    /**
     * Add the contents to the HashMap if there is one existing, otherwise set the value to this HashMap and update the
     * value of this live data
     * @param newData the HashMap of values to add
     */
    fun putAll(newData: HashMap<K, V>) {
        val oldData = value
        value = if (oldData != null) {
            oldData.putAll(newData)
            oldData
        } else {
            newData
        }
    }

    /**
     * Remove a key value pair from this HashMap and update the value of this live data
     * @param key the key to remove
     */
    fun remove(key: K) {
        val oldData = value
        if (oldData != null) {
            oldData.remove(key)
            value = oldData
        }
    }

    /**
     * Clear all data from the backing HashMap and update the value of this live data
     */
    fun clear() {
        val oldData = value
        if (oldData != null) {
            oldData.clear()
            value = oldData
        }
    }

    var value: HashMap<K, V>?
        set(value) = super.setValue(value)
        get() = super.getValue()

}


0
投票

我遇到了同样的问题,并决定在任何地方添加“value = value”或调用另一种方法是太痛苦而且非常容易出错。

所以,我创建了自己的包装集合的类。观察现在将观察集合的内容而不是集合本身。

该代码可在GitHub上找到:ObservableCollections

这是第一版,请原谅任何问题。它还不适用于gradle包含,因此您必须下载它并将其作为库模块添加到您的应用程序中。

目前它包括以下集合:

ArrayDeque
ArrayList
LinkedList
Queue
Stack
Vector

随着时间的推移,将添加更多内容。随意请求特定的。

请报告任何问题。

© www.soinside.com 2019 - 2024. All rights reserved.