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?