Android Studio 4
RxJava2, MVVM.
Approach#1
In my activity:
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()
})
in my 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()
}
}
And my Transport and Retrofit interface
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>>
}
And as result it's work. Nice... but the problem with this approach that Activity know about switch between threads.
So I use another approach.
Approach#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()
})
In my ViewModel:
fun loadData() {
Debug.d(TAG, "loadData:")
filmsListSingle = TransportServiceRxJava.getFilms()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
As you can see switch between threads I move to viewModel.
I think this is a correct way. Only viewModel must need about switch between threads. As result my Activity work only with view widgets (e.g. show toast).
Is this a correct way?