Knowledge of Retrofit, Room, and Coroutines is a must for this guide.
对于本指南,必须具备改造,房间和协同程序的知识。
Part 1 of this Guide Here. (Not mandatory if you know how flows works)
本指南的第1部分 。 (如果您知道流程的工作原理,则不是强制性的)
让我们开始🏁 (Let’s Begin 🏁)
In this guide, we will add a search bar to the android application, which will query all the dog breeds in the database and update the flow based on out query using channels(Github repository here).
在本指南中,我们将向Android应用程序添加搜索栏,该搜索栏将查询数据库中的所有犬种,并基于使用渠道的查询( Github存储库 )更新流。
当前架构 (Current Architecture)
On pressing the “Load More” button, we do a One Shot Request to fetch a dog breed using retrofit which we then save to the Database using Room.
按下“ 加载更多 ”按钮后,我们发出一个单次请求,以使用改造来获取狗的品种,然后使用Room将其保存到数据库中。
This triggers an emission of flow from database of List of Dogs which we then combine with another flow, convert to Live Data and then observe the livedata from the view. (Read More Here)
这触发了“狗的名单”数据库的流发射,然后我们将其与另一个流合并 ,转换为实时数据 ,然后从视图中观察实时数据 。 ( 在这里阅读更多 )
We use the database as the Single Source of Truth.
我们将数据库用作真理的唯一来源。
实施搜索 (Implementing Search)
In this guide we will implement a search bar, that will filter the breeds based on searched query. In the View or MainActivity.kt, pass the searched query to viewModel.setSearchQuery(it)
.
在本指南中,我们将实现一个搜索栏,该搜索栏将根据搜索到的查询过滤品种。 在View或MainActivity.kt中 ,将搜索到的查询传递给viewModel.setSearchQuery( it )
。
search.setOnQueryTextListener(object : SearchView.OnQueryTextListener, androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
newText?.let {
//Pass Search Query to this function in viewmodel
viewModel.setSearchQuery(it)
}
return true
}
}
)
viewModel.dogListLiveData.observe(this, Observer {
adapter.submitList(it)
})
频道介绍 (Introducing Channels)
Channels are a part of the coroutines Library. Think of channels as a pipe. You can send data from one end and receive from another. They are very similar to Non Blocking Queues and can also be used to communicate between coroutines as they support suspending functions for sending as well as receiving data.
通道是协程库的一部分。 将渠道视为管道。 您可以从一端发送数据,也可以从另一端接收数据。 它们与非阻塞队列非常相似,还可以用于在协程之间进行通信,因为它们支持用于发送和接收数据的暂挂功能。
Our implementation will however require a very simple usage of Channels as we won’t be using any suspend functions for this purpose.
但是,我们的实现将需要非常简单地使用Channel,因为我们将不会为此目的使用任何挂起函数。
We will use a ConflatedBroadcastChannel
as this will only broadcast the most recent sent element to all the subscribers.
我们将使用ConflatedBroadcastChannel
因为它将仅向所有订阅者广播最近发送的元素。
private val searchChanel = ConflatedBroadcastChannel<String>()
//We will use a ConflatedBroadcastChannel as this will only broadcast
//the most recent sent element to all the subscribers
fun setSearchQuery(search: String) {
//We use .offer() to send the element to all the subscribers.
searchChanel.offer(search)
}
//Observe this live Data from view and submit the list in adapter.
val dogListLiveData = searchChanel.asFlow() //asFlow() converts received elements from broadcast channels into a flow.
.flatMapLatest { search ->
//We use flatMapLatest as we don't want flows of flows and
//we only want to query the latest searched string.
mainActivityRepository.getSearchedDogs(search)
}
.catch { throwable ->
_snackbar.value = throwable.message
}.asLiveData()
合并和转换流 (Combining and Transforming Flows)
In MainActivityRepository.kt, combine the flow emitted by the database with another flow and perform a transformation on it in Dispatchers.Default thread.
在MainActivityRepository.kt中,将数据库发出的流与另一个流合并,并在Dispatchers.Default线程中对其执行转换。
fun getSearchedDogs(search: String): Flow<List<Dog>> {
return dogDao.getSearchedDogs(search) //Get searched dogs from Room Database
//Combine the result with another flow
.combine(topBreedsFlow) { dogs, topDogs ->
dogs.applyToDog(topDogs)
}
.flowOn(Dispatchers.Default)
//Return the latest values
.conflate()
}
In the interface DogDao.kt
在DogDao.kt接口中
@Query("SELECT * FROM dog WHERE breed LIKE '%' || :search || '%'")
fun getSearchedDogs(search: String?): Flow<List<Dog>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun save(dog: Dog)
you完成了 (And you’re done ✅)
You have implemented a search bar in an application that uses channels to communicate downstream to the database and emits a flow after filtering the query.
您已经在应用程序中实现了搜索栏,该应用程序使用通道与数据库进行下游通信,并在过滤查询后发出流。