【问题标题】:Switch threads only in ViewModel仅在 ViewModel 中切换线程
【发布时间】:2020-07-16 20:55:39
【问题描述】:

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 必须需要在线程之间切换。因此,我的 Activity 仅适用于视图小部件(例如显示 toast)。

这是正确的方法吗?

【问题讨论】:

    标签: android retrofit2 rx-java2


    【解决方案1】:

    将繁重的 Rx 逻辑放在 ViewModel 中是可行的方法。

    这是为了可测试性:片段和活动是重量级的,难以测试。相比之下,ViewModel 更适合测试。

    所以我们按照humble object 模式使片段和活动“愚蠢”。

    片段和活动应该只观察 ViewModel 模型的变化,该模型是一袋原语。这是通过暴露 LiveData 的 ViewModel 完成的。对于 View 的瞬时更改,例如 Toast,Fragment 或 Activity 可以观察在处理时过期的事件流的 LiveData。

    请参阅 Android 架构蓝图和SingleLiveEvent here

    此外,它们不是 RxJava 中的“线程”——它们是调度程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-26
      • 2019-12-11
      • 1970-01-01
      • 1970-01-01
      • 2020-07-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多