Sample Android App to access Discogs API.
This app performs basic REST call to obtain a public list of records from Discogs API, with the idea to test and showcase some Android architecture and coding patterns.
- Kotlin.
- Coroutines.
- Dependency injection with Koin.
- Retrofit + Moshi.
- Architecture Components.
- Modularization.
- Unit Testing.
- Instrumentation Testing with Espresso.
- app (App and MainActivity; Android)
- api (Retrofit Service; Kotlin)
- common-domain (Kotlin)
- collection
| - collection-ui (Fragment and ViewModel; Android)
| - collection-data (Use case; Kotlin)
startKoin(this, listOf(
collectionKoinModule
))private val viewModel: CollectionViewModel by viewModel()@GET("users/{username}/collection/folders/{folder_id}/releases")
fun getCollectionItemsByFolder(
@Path("username") username: String,
@Path("folder_id") folderId: String,
@Query("page") page: Int,
@Query("per_page") perPage: Int
) : Deferred<Response<CollectionItemsByFolderResponse>>private suspend fun requestItems(
folder: String,
page: Int
): Response<CollectionItemsByFolderResponse> {
return discogsService.getCollectionItemsByFolder(
username = "mike513",
folderId = folder,
page = page,
perPage = PAGE_SIZE
).await()
}every {
service.getCollectionItemsByFolder(
username = "mike513",
folderId = "0",
page = 1,
perPage = 20
)
} returns CompletableDeferred(
Response.success(
collectionItemsByFolderResponse
)
)loadingJob = launch(dispatcher) {
val result = collectionUseCase.getCollectionPage("0", page)
when (result) {
is Either.Left -> Log.e("CollectionViewModel", result.a)
is Either.Right -> {
pages[page] = result.b.data
nextPage = result.b.nextPage
}
}
updateCollectionScreenState()
}val viewModel = CollectionViewModel(
collectionUseCase = useCase,
dispatcher = Dispatchers.Unconfined
)
val data = viewModel.liveData.value!!
assertEquals(1, data.size)
val item = data[0] as CollectionItem.AlbumItem
assertEquals(album, item.album)@Test
fun load_single_item_page() {
// Mock the use case to return a single item
val collectionUseCase = mockUseCaseForSingleItem()
// Configure dependency injection to provide ViewModel with Use Case
configureKoin(collectionUseCase)
// Launch Fragment in a Test Activity
launchFragment()
// Assert Album title is displayed in the list
onView(withText("title")).check(matches(isDisplayed()))
}Android Architecute Sample Copyright (C) 2018 Miguel Beltran Febrer
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions.
