Olá, neste projeto, estamos desenvolvendo um app onde eu quero mostrar como eu me comporto no dia a dia do meu dev.
Segue os links dos tópicos 1 e 2 caso você não esteja ciente.
https://medium.com/@nicolaugalves/android-cwb-iniciando-projeto-c3a2c5670879
https://medium.com/@nicolaugalves/android-cwb-parte-2-fbf44ef004cf
Passada essas informações, relembrando onde paramos:
Estavamos no ponto de DI, agora vamos começar a focar em selecionar como fazer nossa chamada, como você sabe, não se deve fazer chamadas na MainThread do Android.
Para isso, vamos usar o Coroutines, que vão nos facilitar no projeto pois não temos problemas com excesso de thread visto que ele consegue fazer mais de um processo, tanto sequêncial como em paralelo dentro de uma única co-routina.
[ Só para adendo, eu estou desenvolvendo em MVP, depois eu vou colocar o ViewModel, LiveData, Databinding, etc ]
Bom, aqui vai meu feedback, demorei umas 3 horas para concluir tanto a implementação como validar meus testes.
Para isso, primeiro temos que colocar no gradle do app e mvp-util nossa dependencia:
//Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.1"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.1"
Você tem que ter cuidado, pois se não souber onde deve usar o coroutines, pode ser que todos seus métodos virem suspend em cascata. Not god. Bom, o lugar certo para usarmos nossa coroutine é no presenter.
E antes, temos que levar em consideração que para usarmos nosso coroutine precisamos ter uma instancia viva de Job para ele reconhecer a classe como ativa a usar esse tipo de função diferente.
Para isso lá no BasePresenter adicionei no gradle para ele ver o coroutine também.
e nossa classe fica assim:
É importante que caso o ON_DESTROY for chamado, nos cancelemos nossos jobs.
No LoginPresenterImpl, para nossos testes passarem, precisamos colocar no construtor as entradas mainDispatcher e ioDispatcher, para em nossos testes podermos mockar esse comportament e nosso teste continuar passando.
class LoginPresenterImpl(
private val getUserUseCase: IGetUserUseCase,
mainDispacher : CoroutineDispatcher,
ioDispacher : CoroutineDispatcher
) :
BasePresenter<ILoginPresenter.View>(), ILoginPresenter.Presenter
Ai, associamos eles ao nosso job da Base,
private val uiScope = CoroutineScope(mainDispacher + job)
val ioScope = CoroutineScope(ioDispacher + job)
e assim, fazemos a chamada no nosso onClickBtnLogin do presenter
override fun onClickBtnLogin(username: String, password: String) {
mView?.showLoading()
uiScope.launch {
getUser(username, password)
}
}
O nosso getUser deve ser suspend visto que esta dentro do launch,
Ficou assim:
private suspend fun getUser(username: String, password: String) {
val userFromUseCase: User? = ioScope.async {
return@async getUserUseCase.execute(username, password)
}.await()
mView?.hideLoading()
userFromUseCase?.let {
mView?.goToHome()
} ?: run {
mView?.errorLogin()
}
}
Agora temos um processo sequêncial, aonde, ele vai esperar acabar o processo e uma vez que temos o resultado do nosso backend ele direciona para a tela.
Uso o Let como garantia que não seja nulo e caso for, dou a alternativa para soltar um erro. Mais a frente no backend vamos criar enums para validar nosso estado de resposta. O login ele é um canal muito importante em todos os apps, principalmente em apps de companias grandes, então todo cuidado é pouco.
Feito isso, não podemos esquecer de nosso DI na mão adicioner isso ao construtor lá onde criamos a instancia única para nosso projeto.
Ficou assim lá no nosso AndroidCWBApplication
private fun injectDependencies() {
AndroidCWBMvpFactory.inject(
Interactors(
getUserUseCaseImpl()
),
AppDispatcherProvider().io(),
AppDispatcherProvider().ui()
)
}
Sim, criei essa classe também chamada AppDispatcherProvider, ela nos retorna o que precisamos ali. No RxAndroid seria o Scheduler, e assim vai..
Para não se perder,
class AppDispatcherProvider : DispatcherProvider {
override fun ui(): MainCoroutineDispatcher {
return Dispatchers.Main
}
override fun io(): CoroutineDispatcher {
return Dispatchers.IO
}
}
e
interface DispatcherProvider {
fun io(): CoroutineDispatcher
fun ui(): CoroutineDispatcher
}
Eu rodei os testes antes e eles estavam falhando com o app funcionando, isso não é legal então a alternativa como falei acima, foi passar no construtor do presenter o io e ui visto que o mockito tava quebrando com o coroutines. Assim o meu teste atualizou assim,
Assim, rodando os testes veremos que todos eles passam de novo.
E bom, é isso, ficamos por aqui, nesta parte do projeto esperava construir o BD, mas vamos deixar para a próxima, foi muito importante primeiro setarmos a chamada com a coroutine e validarmos nosso testes.
Na próxima parte do projeto ai sim vamos colocar o BD, eu já estou familiarizado com o Room, então bem provavel que usemos isso. A ideia, é que depois começemos a preencher esse bd com um Json.file dos nossos jogadores de Android. Ai uma vez montado isso, a gente cria um servidor pelo back4apps com essas informações para consumirmos com Retrofit ou qualquer outra lib. Por isso esse passo a passo offline.
Então é isso, até a próxima.
Att, Carlos Nicolau Galves.