本文说明如何使用flow来代替LiveData实现mvvm
免责声明:flow 和 channel处于实验阶段,后续api会可能变化比较大。
使用协程过程中发现,Kotlin的flow 和channel 还在试验阶段,所以一直没用上。但是因为LiveData的设计是不好处理Backpressure的,熟悉Rx的同学,知道Rx的同学知道,Rx官方文档给我们展示了如何处理背压。但是LiveData真的有时候不好用,但是要实现mvvm,我们却不得不用它。
但是其实我们完全可以使用flow来代替它。而且使用了之后会发现:真。。真 香!!!

下面我通过实现一个搜索功能,不使用LiveData只使用flow 来实现mvvm。LiveData,再见~~
首先上才艺:(github链接 :github.com/JJJsn/struc…)

直接上代码:
@ExperimentalCoroutinesApi
@FlowPreview
class SearchBarActivity :AppCompatActivity(){
lateinit var adapter: SearchAdapter //展示搜索结果的recyclerview的适配器
val viewModel by viewModels<SearchBarViewModel>(
SearchBarViewModelFactory() ) //使用 activity-ktx包里面的扩展函数减少模板代码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
rv_search_result.adapter=SearchAdapter().also { adapter=it } //设置recyclerview
rv_search_result.layoutManager=LinearLayoutManager(this)
et_keyWord.doAfterTextChanged { keyWord->
with(viewModel){
channel.offer(keyWord.toString()) //给channel发送数据
}
}
lifecycleScope.launchWhenStarted {
//当我们的activity处于活跃状态的时候 ,才会collect我们的flow。
//实现和LiveData一摸一样的效果
viewModel.searchResultFlow.collect { searchResult ->
when(searchResult){
is Result.Loading -> {}
is Result.Error-> { showMessage(searchResult.toString())}
is Result.Success -> {adapter.submitList(searchResult.data) }
}
}
}
}
}然后是我们的viewModel:
@ExperimentalCoroutinesApi
class SearchBarViewModel :ViewModel() {
//自动处理 backpressure ,真是香
val channel =ConflatedBroadcastChannel<String>() //channel 的缓存大小为 1
@FlowPreview
val searchResultFlow: Flow<Result<List<String>>> =channel.asFlow()
.map { key ->
delay(200)
Result.Success(repositoty.filter {
it.contains(key)
}) as Result<List<String>>
}
.onStart {}
.flowOn(Dispatchers.IO) //这行代码上面的代码都会在 IO线程执行。
.catch { e:Throwable ->
emit(Result.Error(e as Exception))
}
override fun onCleared() {
super.onCleared()
channel.close()
}
val repositoty= mutableListOf<String>().apply { //测试数据
add("123我爱你");add("17岁");add("123木头人")
add("11111");add("1234");add("1990");add("1111");add("111");add("119")
add("1121"); add("112");add("1111")
add("111 Summer Classics");add("111111");add("111 (Centoundici)");
add("11:11 (Amended)");
add("11111101");add("11112")
add("1111111");add("11111101");
add("11111 (feat. Jake Candieux, Dan Monic..)");add("11111111")
}
}欧克,我们没有使用LiveData,实现了一摸一样的效果!!
这里重点说下ConflatedBroadcastChannel
我也不太能说清楚,直接上图上链接:
图片来自文章 proandroiddev.com/kotlin-coro…
channel是啥?:

图1:channel的介绍
channel的缓存类型,本文用的是Conflated:

图2:channel的缓存类型
参考文献:
1. Jag Saund Dive into Croutines and Channels
proandroiddev.com/kotlin-coro…
2.Süleyman Fatih Giriş Use LiveData & Flow in MVVM
proandroiddev.com/kotlin-coro…
3. Android_开发者 协程 Flow的最佳实践
4. 如何使用Flow和channel的sample,Sean McQuillan
fragmentedpodcast.com/episodes/18…