android - 实现 MVVM LiveData RxJava Dagger Databinding 的正确结构?

标签 android data-binding rx-java2 android-livedata dagger

主 Activity

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()
                }
            }
        })
    }
}

MainViewModelFactory
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
}

MainViewModel
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}")
                    }
                })
    }
}

MainRepository
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 中我调用接口(interface)方法并在 ViewModel 中实现它,也在响应中我将响应保存到 db。但是,这是一种私有(private)方法,在单元测试中不能以适当的方式进行测试(因为它是私有(private)的)。在完成一种方法时调用其他方法的最佳做法是什么,或者我必须在使用该接口(interface)的实现类中实现所有方法。

最佳答案

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

关于android - 实现 MVVM LiveData RxJava Dagger Databinding 的正确结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58109723/

相关文章:

c# - 为什么单击按钮后我的更新按钮文本不显示?

java - RxJava 2-如何在发生错误时取消无限流并进行处理?

rest - 如何使用 micronaut 传输来自 JPA 的数据流?

Android: Activity 在 startActivity() 之后立即隐藏

android - 如何在android中进行实时音频流时处理电话

ContextMenu : direct vs. 资源中的 WPF 数据绑定(bind)

c# - 绑定(bind)到集合的 View 并在 WPF 中调用 ToString()

java - 在后台线程上处理订阅的链

android - 如何在React Native中使用OpenCV

android - Azure上托管的Asp.net后端和Web API Web服务如何将推送通知发送到移动应用程序?