仅在ViewModel中切换线程



Android Studio 4

RxJava2、MVVM。

方法#1

在我的活动中:

val dispose = filmsRxJavaViewModel.filmsListSingle
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe( {// call before .doOnTerminate()
Debug.d(TAG, "initLogic: doOnSubscribe:")
binding.progressBarLayout.containerProgressBarLayout.setVisibility(View.VISIBLE)
})
.doOnTerminate({// call before .subscribe()
Debug.d(TAG, "initLogic: doOnTerminate:")
binding.filmsSwipeRefreshLayout.isRefreshing = false
binding.progressBarLayout.containerProgressBarLayout.setVisibility(View.GONE)
})
// Only after call subscribe() then execute network request
.subscribe({ filmsList -> // success
Debug.d(TAG, "initLogic: subscribe: success")
// Hide swipe to refresh icon animation
if (filmsList.size > 0) { // list<Film>
filmItemListDataBindingAdapter!!.updateData(filmsList)
} else {
binding.filmsRecyclerView.visibility = View.GONE
binding.emptyLayoutContainer.root.visibility = View.VISIBLE
}
}, {// error
throwable ->
Debug.e(TAG, "initLogic: subscribe: error = $throwable")
Toast.makeText(this, throwable.message, Toast.LENGTH_LONG).show()
})

在我的ViewModel中:

class FilmsRxJavaViewModel(application: Application) : AndroidViewModel(application) {
companion object {
private val TAG = FilmsRxJavaViewModel::class.java.name
}
lateinit var filmsListSingle: Single<List<Film>>
init {
Debug.d(TAG, "init:")
loadData()
}
fun loadData() {
Debug.d(TAG, "loadData:")
filmsListSingle = TransportServiceRxJava.getFilms()
}
}

我的运输和改装接口

fun getFilms() : Single<List<Film>> {
return testRxJavaRestClient.getFilms()
}
import io.reactivex.Single
import retrofit2.http.GET
interface TestRxJavaRestClient {
@GET("films")
fun getFilms(): Single<List<Film>>
}

结果就是工作。美好的但Activity知道的这种方法的问题是在线程之间切换。

所以我用了另一种方法。

方法#2

val dispose = filmsRxJavaViewModel.filmsListSingle
.doOnSubscribe( {// call before .doOnTerminate()
Debug.d(TAG, "initLogic: doOnSubscribe:")
binding.progressBarLayout.containerProgressBarLayout.setVisibility(View.VISIBLE)
})
.doOnTerminate({// call before .subscribe()
Debug.d(TAG, "initLogic: doOnTerminate:")
binding.filmsSwipeRefreshLayout.isRefreshing = false
binding.progressBarLayout.containerProgressBarLayout.setVisibility(View.GONE)
})
// Only after call subscribe() then execute network request
.subscribe({ filmsList -> // success
Debug.d(TAG, "initLogic: subscribe: success")
// Hide swipe to refresh icon animation
if (filmsList.size > 0) { // list<Film>
filmItemListDataBindingAdapter!!.updateData(filmsList)
} else {
binding.filmsRecyclerView.visibility = View.GONE
binding.emptyLayoutContainer.root.visibility = View.VISIBLE
}
}, {// error
throwable ->
Debug.e(TAG, "initLogic: subscribe: error = $throwable")
Toast.makeText(this, throwable.message, Toast.LENGTH_LONG).show()
})

在我的ViewModel中:

fun loadData() {
Debug.d(TAG, "loadData:")
filmsListSingle = TransportServiceRxJava.getFilms()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}

正如您所看到的,在线程之间切换,我转到viewModel。

我认为这是一个正确的方式。只有viewModel必须在线程之间进行切换。因此,我的"活动"仅适用于视图小部件(例如show toast(。

这是正确的方式吗?

将繁重的Rx逻辑放入ViewModel中是可行的。

这是为了测试性:碎片和活动是重量级的,很难测试。相比之下,ViewModel可以进行测试。

所以我们制作了《碎片与活动》;愚蠢的";遵循谦逊的对象模式。

Fragment和Activities应该只观察ViewModel模型的变化,该模型是一个基元包。这是通过ViewModel公开LiveData来完成的。对于视图的临时更改,如Toast,Fragment或Activity可以观察到在处理时过期的事件流的LiveData。

请参阅此处的Android架构蓝图和SingleLiveEvent

而且,它们不是";线程";在RxJava中,它们是调度器。

最新更新