Escolar Documentos
Profissional Documentos
Cultura Documentos
Capítulo 6 : Montando um
Repositório
Requerimentos técnicos
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 1/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 2/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
querer trocar Retrofit ou Room por alternativas. Se quisermos trocar essas bi-
bliotecas por outras, corremos o risco de mudanças na classe RepositoryImpl ,
que viola o princípio de responsabilidade única. A solução para isso é como a
solução que tivemos para resolver as dependênciasentre os casos de uso e os
repositórios, e isso é inverter as dependências entre o repositório e as fontes
de dados. Isso se pareceria com o seguinte:
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 3/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 4/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
Criando repositórios
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 5/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
interface UserRepository {
fun getUser(id: String): Flow<User>
}
Aqui temos uma interface chamada UserRepository que é responsável por bus-
car as informações do usuário em um fluxo Kotlin.
interface UserRemoteDataSource {
fun getUser(id: String): Flow<User>
}
Neste caso, temos uma interface semelhante a como UserRepository é definido
com um método simples pararecuperar um objeto User . Agora podemos im-
plementar UserRepository para usar esta fonte de dados:
interface UserLocalDataSource {
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 6/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
class UserRepositoryImpl(
valor privado userRemoteDataSource:
UserRemoteDataSource,
valor privado userLocalDataSource:
UserLocalDataSource
): UserRepository {
override fun getUser(id: String): Flow<User> =
userRemoteDataSource.getUser(id)
.em cada {
userLocalDataSource.insertUser(it)
}
}
Isso representa um caso de uso simples para fontes de dados, mas podemos
usar repositórios para melhorar a experiência do usuário. Por exemplo, pode-
mos alterar a implementação do repositório para retornar odados salvos e
têm um método separado para buscar os dados remotamente. Podemos apro-
veitar os fluxos, que podem emitir vários usuários em um fluxo:
interface UserLocalDataSource {
suspender a diversão insertUser(user: User)
fun getUser(id: String): Flow<User>
}
No exemplo anterior, adicionamos o método getUser para recuperar um ob-
jeto User , que foi persistido localmente. Precisaremos modificar a abstração
do repositório da seguinte forma:
interface UserRepository {
fun getUser(id: String): Flow<User>
fun refreshUser(id: String): Flow<User>
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 7/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
class UserRepositoryImpl(
valor privado userRemoteDataSource:
UserRemoteDataSource,
valor privado userLocalDataSource:
UserLocalDataSource
): UserRepository {
override fun getUser(id: String): Flow<User> =
userLocalDataSource.getUser(id)
override fun refreshUser(id: String): Flow<User> =
userRemoteDataSource.getUser(id)
.em cada {
userLocalDataSource.insertUser(it)
}
}
Aqui, retornamos o usuário persistente no método getUser e, no método re‐
freshUser , agora buscamos os dados remotos e os inserimos localmente. Se es-
class UserRepositoryImpl(
valor privado userRemoteDataSource:
UserRemoteDataSource,
valor privado userLocalDataSource:
UserLocalDataSource
): UserRepository {
valor privado usersFlow = MutableStateFlow
(emptyMap<String, User>().toMutableMap())
override fun getUser(id: String): Flow<User> =
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 8/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
usersFlow.flatMapLatest {
val usuário = it[id]
if (usuário != null) {
flowOf(usuário)
} senão {
userLocalDataSource.getUser(id)
.onEach { persistedUser ->
saveUser(usuário persistente)
}
}
}
override fun refreshUser(id: String): Flow<User> =
userRemoteDataSource.getUser(id)
.em cada {
saveUser(it)
userLocalDataSource.insertUser(it)
}
diversão privada saveUser(user: User) {
val map = usersFlow.value
mapa[user.id] = usuário
usersFlow.value = map
}
}
Aqui, adicionamos um novo objeto MutableStateFlow , que conterá um mapa
no qual as chaves são representadas pelos IDs dos usuários e os valores são os
usuários. No método getUser , verificamos se o usuário está armazenado na
memória e retornamos o valor da memória se estiver presente, caso contrário,
obtemos os dados persistentes, que depois armazenaremos na memória. No
método refreshUser , persistimos o valor na memória e persistimos os dados
localmente.
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 9/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
Nesta seção, vimos como podemos criar repositórios e como eles podem ser
usados para gerenciar dados em um aplicativo. Na seção a seguir, veremos um
exercício no qual criaremos repositórios para um aplicativo.
DataSource , que terá métodos para inserir uma lista de usuários e obter
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 11/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 12/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
}
10. No pacote data_source , crie umnovo pacote chamado local .
11. No pacote local , crie a interface LocalUserDataSource :
interface LocalUserDataSource {
fun getUsers(): Flow<List<User>>
suspender diversão addUsers(users: List<User>)
}
12. No pacote local , crie a interface LocalPostDataSource :
interface LocalPostDataSource {
fun getPosts(): Flow<List<Post>>
suspender diversão addPosts(posts: List<Post>)
}
13. No pacote local , crie o pacote LocalInteractionDataSource :
interface LocalInteractionDataSource {
fun getInteraction(): Flow<Interaction>
suspend fun saveInteraction(interaction:
Interaction)
}
14. Ao lado do pacote data_source , crieum novo pacote chamado repositório .
15. No pacote de repositório , crie a classe UserRepositoryImpl :
class UserRepositoryImpl @Inject construtor(
valor privado remoteUserDataSource:
RemoteUserDataSource,
valor privado localUserDataSource:
LocalUserDataSource
): UserRepository {
substituir fun getUsers(): Flow<List<User>> =
remoteUserDataSource.getUsers()
.em cada {
localUserDataSource.addUsers(it)
}
override fun getUser(id: Long): Flow<User> =
remoteUserDataSource.getUser(id)
.em cada {
localUserDataSource.addUsers(listOf(it))
}
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 13/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 14/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
}.flatMapLatest {
getInteração()
}
}
Aqui, estamos apenas interagindo com a fonte de dados local para ler e arma-
zenar os dados.
18. Agora queremos usar Hilt paravincule a abstração do repositório com a im-
plementação, então precisaremos criar um pacote chamado injeção pró-
ximo aos pacotes data_source e repositório .
19. Dentro do pacote de injeção , crie uma classe chamada RepositoryModule :
@Módulo
@InstallIn(SingletonComponent::class)
classe abstrata RepositoryModule {
@Binds
diversão abstrata
bindPostRepository(postRepositoryImpl
: PostRepositoryImpl): PostRepository
@Binds
diversão abstrata bindUserRepository
(userRepositoryImpl: UserRepositoryImpl):
UserRepository
@Binds
diversão abstrata bindInteractionRepository
(interactionRepositoryImpl:
InteractionRepositoryImpl):
InteractionRepository
}
20. Para testar a unidade do código, agora precisaremos criar uma nova pasta
chamada resources no testepasta do módulo de repositório de dados .
21. Dentro da pasta de recursos, crie uma pasta chamada mockito-extensions
e, dentro dessa pasta, crie um arquivo chamado
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 15/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
texto: mock-maker-inline .
22. Crie uma classe UserRepositoryImplTest para teste de unidade dos métodos
UserRepositoryImpl :
class UserRepositoryImplTest {
valor privado remoteUserDataSource =
mock<RemoteUserDataSource>()
valor privado localUserDataSource =
mock<LocalUserDataSource>()
private val repositoryImpl = UserRepositoryImpl
(remoteUserDataSource, localUserDataSource)
}
23. Na classe UserRepositoryImplTest , adicione um método de teste para cada
repositóriométodo:
class UserRepositoryImplTest {
…
@ExperimentalCoroutinesApi
@Teste
fun testGetUsers() = runBlockingTest {
val usuários = listOf(Usuário(1, "nome", "nome
de usuário",
"o email"))
sempre(remoteUserDataSource.getUsers()).
thenReturn(flowOf(usuários))
val resultado =
repositoryImpl.getUsers().first()
assertEquals(usuários, resultado)
verifique(localUserDataSource).addUsers(usuári
os)
}
@ExperimentalCoroutinesApi
@Teste
fun testGetUser() = runBlockingTest {
val id = 1L
val user = User(id, "nome", "nome de usuário",
"o email"
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 16/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
)
sempre(remoteUserDataSource.getUser(id))
.thenReturn(flowOf(usuário))
val resultado = repositórioImpl.getUser(id).
primeiro()
assertEquals(usuário, resultado)
verifique(localUserDataSource).addUsers(listOf
(usuário))
}
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 17/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
val resultado =
repositórioImpl.getPosts().first()
Assert.assertEquals(postagens, resultado)
verifique(localPostDataSource).addPosts(posts)
}
@ExperimentalCoroutinesApi
@Teste
fun testGetPost() = runBlockingTest {
val id = 1L
val post = Post(id, 1, "título", "corpo")
sempre(remotePostDataSource.getPost(id)).thenR
eturn(flowOf(post))
val resultado =
repositórioImpl.getPost(id).first()
Assert.assertEquals(postagem, resultado)
verifique(localPostDataSource).addPosts(listOf
(post))
}
}
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 18/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 19/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
Resumo
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 20/21
26/10/2022 21:44 Chapter 6: Assembling a Repository | Clean Android Architecture
Apoiar Sair
https://learning.oreilly.com/library/view/clean-android-architecture/9781803234588/B18320_06_ePub.xhtml#_idParaDest-77 21/21