如何使用 LiveData 进行搜索?

How to use LiveData for searching?

我有一个 ViewModel,它具有 class 课程

数组列表的 MutableLiveData
private var coursesList: MutableLiveData<ArrayList<Course>> = MutableLiveData()

此 coursesList 填充了从 API(通过 Retrofit)获得的数据:coursesList.postValue(response.body())

现在,用户可以通过课程名称搜索课程。我的搜索功能是遍历 coursesList 的元素并检查其名称是否与用户键入的名称相同。它 returns 一个 arrayList,其中包含以键入的名称开头的课程(此列表稍后被发送到一个片段,该片段将其传递给一个适配器以显示在 recyclerview 中):

fun getCoursesList(): MutableLiveData<ArrayList<Course>> {
        return coursesList
}

fun searchCourses(searchString: String): ArrayList<Course> {

    val resultsList: ArrayList<Course> = ArrayList()

    if (getCoursesList().value == null) return resultsList

    if (getCoursesList().value!!.size > 0) {
       
        for (course in getCoursesList().value!!.iterator()) {
            if (course.name.toLowerCase(Locale.ROOT).startsWith(searchString)) {
                resultsList.add(course)
            }
        }
    }
    resultsList.sortBy { it.price }
    return resultsList
}

这个功能有效,但我的导师要求我使用 LiveData 进行搜索,但没有给出任何额外的提示。

所以我的问题是如何使用 LiveData 进行搜索?我试图寻找答案,我看到一些人使用了 LiveDataTransformations.switchMap,但他们都在使用 RoomDAO,我无法根据我的代码对其进行调整。

非常感谢任何帮助。提前致谢。

我很难猜到想要的结果,但一个可能的解决方案是对搜索的字符串也使用实时数据。然后将它们与 coursesList 实时数据组合成搜索课程的实时数据,例如这样。

    val searchStringLiveData: MutableLiveData<String> = MutableLiveData()
    val coursesListLiveData: MutableLiveData<ArrayList<Course>> = MutableLiveData()
    val searchedCourses: MediatorLiveData<ArrayList<Course>> = MediatorLiveData()

    init {
        searchedCourses.addSource(searchStringLiveData) {
            searchedCourses.value = combineLiveData(searchStringLiveData, coursesListLiveData)
        }
        searchedCourses.addSource(coursesListLiveData) {
            searchedCourses.value = combineLiveData(searchStringLiveData, coursesListLiveData)
        }
    }


    fun combineLiveData(searchStringLiveData: LiveData<String>, coursesListLiveData: LiveData<ArrayList<Course>> ): ArrayList<Course> {
        // your logic here to filter courses
        return ArrayList()
    }

我没有 运行 代码,所以我不能 100% 确定它是否有效,但我的想法是,每当两个实时数据中的任何一个更改值、搜索字符串或课程时,合并执行函数并将结果设置为 searchedCourses 中介实时数据的值。此外,为了简单起见,我省略了过滤逻辑。

也许这对你有一点帮助,

class YourViewModel(
   private val courcesRepository: CourcesRepository
) : ViewModel() {

// Private access - mutableLiveData!
private val _coursesList = MutableLiveData<ArrayList<Course>>()

// Public access - immutableLiveData
val coursesList: LiveData<ArrayList<Course>>
    get() = _coursesList

init {
    // mutableLiveData initialize, automatic is immutable also initialize
    _coursesList.postValue(getCourses())
}

// Here you get your data from repository
private fun getCourses(): ArrayList<Course> {
    return courcesRepository.getCources()
}

// Search function
fun searchCourses(searchString: String) {

    // you hold your data into this methode
    val list: ArrayList<Course> = getCources()

    if (searchString.isEmpty()) {

        // here you reset the data if search string is empty
        _coursesList.postValue(list)
    } else {

        // here you can search the list and post the new one to your LiveData
        val filterList = list.filter {
            it.name.toLowerCase(Locale.ROOT).startsWith(searchString)
        }
        filterList.sortedBy { it.price }
        _coursesList.postValue(filterList)
    }
}

}

第一个提示 是你应该像下面那样使用 LiveData,这也是 google 的喷气背包团队推荐的。原因是你可以封装LivaData。

第二个技巧是您应该使用 kotlin 惯用的方式来过滤列表。您的代码可读且速度更快。

至少 创建一个存储库 class 来分离应用中的关注点是个好主意。

以及一些对您有用的链接:

https://developer.android.com/jetpack/guide

https://developer.android.com/topic/libraries/architecture/livedata

希望对你有所帮助