首页 > 解决方案 > 实现 MVVM LiveData RxJava Dagger Databinding 的正确结构?

问题描述

主要活动

class MainActivity : AppCompatActivity() {
    @Inject
    lateinit var mainViewModelFactory: mainViewModelFactory
    private lateinit var mainActivityBinding: ActivityMainBinding
    private lateinit var mainViewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mainActivityBinding = DataBindingUtil.setContentView(
                this,
                R.layout.activity_main
        )

        mainActivityBinding.rvmainRepos.adapter = mainAdapter
        AndroidInjection.inject(this)
        mainViewModel =
                ViewModelProviders.of(
                        this@MainActivity,
                        mainViewModelFactory
                )[mainViewModel::class.java]
        mainActivityBinding.viewmodel = mainViewModel
        mainActivityBinding.lifecycleOwner = this
        mainViewModel.mainRepoReponse.observe(this, Observer<Response> {
            repoList.clear()
            it.success?.let { response ->
                if (!response.isEmpty()) {
                    //     mainViewModel.saveDataToDb(response)
                    //     mainViewModel.createWorkerForClearingDb()
                }
            }
        })
    }
}

主视图模型工厂

class MainViewModelFactory @Inject constructor(
        val mainRepository: mainRepository
) : ViewModelProvider.NewInstanceFactory() {

    override fun <T : ViewModel?> create(modelClass: Class<T>) =
            with(modelClass) {
                when {
                    isAssignableFrom(mainViewModel::class.java) -> mainViewModel(
                            mainRepository = mainRepository
                    )
                    else -> throw IllegalArgumentException("Unknown ViewModel class: ${modelClass.name}")
                }
            } as T
}

主视图模型

class MainViewModel(
        val mainRepository: mainRepository
) : ViewModel() {

    private val compositeDisposable = CompositeDisposable()
    val mainRepoReponse = MutableLiveData<Response>()
    val loadingProgress: MutableLiveData<Boolean> = MutableLiveData()
    val _loadingProgress: LiveData<Boolean> = loadingProgress
    val loadingFailed: MutableLiveData<Boolean> = MutableLiveData()
    val _loadingFailed: LiveData<Boolean> = loadingFailed
    var isConnected: Boolean = false

    fun fetchmainRepos() {
        if (isConnected) {
            loadingProgress.value = true
            compositeDisposable.add(
                    mainRepository.getmainRepos().subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe({ response ->
                                run {
                                    saveDataToDb(response)
                                    )
                                }
                            },
                                    { error ->
                                        processResponse(Response(AppConstants.Status.SUCCESS, null, error))
                                    }
                            )
            )
        } else {
            fetchFromLocal()
        }
    }

    private fun saveDataToDb(response: List<mainRepo>) {
        mainRepository.insertmainUsers(response)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .subscribe(object : DisposableCompletableObserver() {
                    override fun onComplete() {
                        Log.d("Status", "Save Success")
                    }

                    override fun onError(e: Throwable) {
                        Log.d("Status", "error ${e.localizedMessage}")
                    }
                })
    }
}

主存储库

interface MainRepository {

    fun getmainRepos(): Single<List<mainRepo>>

    fun getAllLocalRecords(): Single<List<mainRepo>>

    fun insertmainUsers(repoList: List<mainRepo>): Completable
}

MainRepositoryImpl

class mainRepositoryImpl @Inject constructor(
        val apiService: GitHubApi,
        val mainDao: AppDao
) : MainRepository {

    override fun getAllLocalRecords(): Single<List<mainRepo>> = mainDao.getAllRepos()

    override fun insertmainUsers(repoList: List<mainRepo>) :Completable{
        return   mainDao.insertAllRepos(repoList)
    }

    override fun getmainRepos(): Single<List<mainRepo>> {
        return apiService.getmainGits()
    }
}

我对使用 LiveData 和 Rxjava 实现 MVVM 感到非常困惑,在我的 MainViewModel 中我调用接口方法并在 ViewModel 中实现它,也在响应中我将响应保存到 db。但是,这是一种私有方法,在单元测试中不能以适当的方式进行测试(因为它是私有的)。在完成一种方法时调用其他方法的最佳做法是什么,或者我必须在使用该接口的实现类中实现所有方法。

标签: androiddata-bindingrx-java2android-livedatadagger

解决方案


如果您尝试遵循干净的架构模式,您的 ViewModel 不应该关心您如何获取数据。从本地或远程源获取数据的逻辑应该在存储库中,在最坏的情况下您还可以保存响应。在这种情况下,由于您有方法的联系人,您可以轻松地测试它们。理想情况下,您可以将其分解得更多——添加用例/交互器。


推荐阅读