Правильная структура реализации MVVM LiveData RxJava Dagger Databger? - PullRequest
1 голос
/ 26 сентября 2019

MainActivity

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

Я очень запутался с реализацией MVVM с LiveData и Rxjava, в моемMainViewModel Я вызываю метод интерфейса и реализую его внутри ViewModel, также в ответе я сохраняю ответ в db.Тем не менее, это закрытый метод, который не может быть протестирован в модульном тестировании надлежащим образом (потому что он закрытый).Какова лучшая практика для вызова других методов по завершении одного метода, или я должен реализовать все методы внутри класса реализации, который использует интерфейс.

1 Ответ

0 голосов
/ 26 сентября 2019

Ваша ViewModel не должна заботиться о том, как вы получаете данные, если вы пытаетесь следовать шаблону чистой архитектуры.Логика для извлечения данных из локальных или удаленных источников должна быть в хранилище в худшем случае, где вы также можете сохранить ответ.В этом случае, поскольку у вас есть контакт для методов, вы можете легко проверить их.В идеале вы могли бы разбить его еще больше - добавив Usecases / Interactors.

...