Last active
June 8, 2021 12:28
-
-
Save quentin41500/f93978d97f5008cde387db19ce5e2ef6 to your computer and use it in GitHub Desktop.
Using Sealed class and LiveData to handle network request through the repository layer.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Observable manager for saving the [Cart]'s resource information. | |
*/ | |
class CartManager : LiveData<Resource<Cart?>>() { | |
init { | |
value = Success(null) | |
} | |
/** | |
* Set the [Cart] value and notifies observers. | |
*/ | |
internal fun set(cart: Cart) { | |
postValue(Success(cart)) | |
} | |
/** | |
* Clear any information from the device. | |
*/ | |
internal fun clear() { | |
postValue(Success(null)) | |
} | |
/** | |
* Signals that the resource information is being retrieved from network. | |
*/ | |
internal fun loading() { | |
postValue(Loading()) | |
} | |
/** | |
* Signals that an error occurred when trying to fetch the resource information. | |
*/ | |
internal fun error(t: Throwable) { | |
postValue(Failure(t)) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* [Cart] repository class in charge of providing api for getting and updating a [Cart] data. | |
*/ | |
class CartRepository(private val service: RetrofitApi, private val cartManager: CartManager) { | |
fun getCartResource(): LiveData<Resource<Cart?>> = cartManager | |
/** | |
* Get a [Cart]. | |
*/ | |
suspend fun get() { | |
withContext(Dispatchers.IO) { | |
try { | |
cartManager.loading() | |
val cart = service.getCart().await() | |
cartManager.set(cart) | |
} catch (e: Exception) { | |
cartManager.error(e) | |
} | |
} | |
} | |
/** | |
* Add a [Cart] shipping information. | |
*/ | |
suspend fun addShippingAddress(shipping: ShippingAddress) { | |
withContext(Dispatchers.IO) { | |
try { | |
cartManager.loading() | |
val cart = service.addShippingAddress(shipping).await() | |
cartManager.set(cart) | |
} catch (e: Exception) { | |
cartManager.error(e) | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CheckoutActivity : AppCompatActivity() { | |
private lateinit var vm: CheckoutViewModel | |
override fun onCreate(savedInstanceState: Bundle?) { | |
// Initialization | |
... | |
vm.cart.observe(this, Observer { resource -> | |
when (resource) { | |
is Loading -> showLoading() | |
is Success -> { | |
displayCart(resource.data) // Do something with your data. | |
hideLoading() | |
} | |
is Failure -> { | |
showError(resource.throwable) // Do something with your error. | |
hideLoading() | |
} | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CheckoutViewModel(repo: CartRepository) : ViewModel() { | |
/** | |
* Live data for [Cart] information. | |
*/ | |
val cart: LiveData<Resource<Cart?>> = repo.getCartResource() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Represents a network bound resource. Each subclass represents the resource's state: | |
* - [Loading]: the resource is being retrieved from network. | |
* - [Success]: the resource has been retrieved (available in [Success.data] field) | |
* - [Failure]: the resource retrieving has failed (throwable available in [Failure.throwable] field) | |
*/ | |
sealed class Resource<out T> { | |
class Loading<out T> : Resource<T>() | |
data class Success<out T>(val data: T) : Resource<T>() | |
data class Failure<out T>(val throwable: Throwable) : Resource<T>() | |
} |
I originally was using a variable but realized later I didn't need it. You can just pass the created objects to live data right away.
postValue(Success(null))
I will make the edit.
What if we use a boolean in loading so we have to just pass boolean on completion once, and not twice at both error and success case ?
What if you're integrating a database layer? Would we still be observing the resource in the UI if you want to fetched cached objects?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello! I've read your article. This implementation is exactrly what I looked for. But due to my experience, I dont understand what resource is in CartManager:
Thanks!