Skip to content

Instantly share code, notes, and snippets.

View sberoch's full-sized avatar

Santiago Beroch sberoch

  • Zarate, Buenos Aires, Argentina
View GitHub Profile
fun <T, A> performGetOperation(databaseQuery: () -> LiveData<T>,
networkCall: suspend () -> Resource<A>,
saveCallResult: suspend (A) -> Unit): LiveData<Resource<T>> =
liveData(Dispatchers.IO) {
emit(Resource.loading())
val source = databaseQuery.invoke().map { Resource.success(it) }
emitSource(source)
val responseStatus = networkCall.invoke()
if (responseStatus.status == SUCCESS) {
class CharacterRepository @Inject constructor(
private val remoteDataSource: CharacterRemoteDataSource,
private val localDataSource: CharacterDao
) {
fun getCharacter(id: Int) = performGetOperation(
databaseQuery = { localDataSource.getCharacter(id) },
networkCall = { remoteDataSource.getCharacter(id) },
saveCallResult = { localDataSource.insert(it) }
)
@Dao
interface CharacterDao {
@Query("SELECT * FROM characters")
fun getAllCharacters() : LiveData<List<Character>>
@Query("SELECT * FROM characters WHERE id = :id")
fun getCharacter(id: Int): LiveData<Character>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(characters: List<Character>)
@Entity(tableName = "characters")
data class Character(
val created: String,
val gender: String,
@PrimaryKey
val id: Int,
val image: String,
val name: String,
val species: String,
val status: String,
@Database(entities = [Character::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun characterDao(): CharacterDao
companion object {
@Volatile private var instance: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase =
instance ?: synchronized(this) { instance ?: buildDatabase(context).also { instance = it } }
abstract class BaseDataSource {
protected suspend fun <T> getResult(call: suspend () -> Response<T>): Resource<T> {
try {
val response = call()
if (response.isSuccessful) {
val body = response.body()
if (body != null) return Resource.success(body)
}
return error(" ${response.code()} ${response.message()}")
class CharacterRemoteDataSource @Inject constructor(
private val characterService: CharacterService
): BaseDataSource() {
suspend fun getCharacters() = getResult { characterService.getAllCharacters() }
suspend fun getCharacter(id: Int) = getResult { characterService.getCharacter(id) }
}
interface CharacterService {
@GET("character")
suspend fun getAllCharacters() : Response<CharacterList>
@GET("character/{id}")
suspend fun getCharacter(@Path("id") id: Int): Response<Character>
}
viewModel.characters.observe(viewLifecycleOwner, Observer {
when (it.status) {
Resource.Status.SUCCESS -> {
progress_bar.visibility = View.GONE
if (!it.data.isNullOrEmpty()) adapter.setItems(ArrayList(it.data))
}
Resource.Status.ERROR ->
Toast.makeText(activity, it.message, Toast.LENGTH_SHORT).show()
Resource.Status.LOADING ->
data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
enum class Status {
SUCCESS,
ERROR,
LOADING
}
companion object {
fun <T> success(data: T): Resource<T> {