Reputation: 435
I have integration with backend made with retrofit. My project architecture is similar to known GithubBrowserSample proposed by Google as example. This means, my ViewModel has some LiveData that can be observed
Any request can throw "401 unauthorized" and I would like to redirect to login fragment. And I can do this when checking details of errors at fragment during observing
viewModel.user.observe(viewLifecycleOwner, { response ->
if (response.status == Status.SUCCESS) {
// do work there
} else if (response.status == Status.ERROR) {
// check does this 401 and redirect
}
})
But, I have a lot of such places in my app and I need some mechanism for listening of 401 and redirect which can be applied to all places out of the box without checking in every place
Let's say, some wrapper, some utils to reuse check for specific error
Upvotes: 0
Views: 70
Reputation: 1701
If the error you want to handle is specific to 401 Unauthorized
, you can implement Authenticator
and attach it to your okhttp
.
First, create your Authenticator
class
class YourAuthenticator : Authenticator {
// This callback is only called when you got 401 Unauthorized response
override fun authenticate(route: Route?, response: Response): Request? {
// Navigate to Login fragment
}
}
Then, add Authenticator
to your okhttp builder
val yourAuthenticator = YourAuthenticator()
val okHttp = OkHttpClient.Builder()
.authenticator(yourAuthenticator)
.build()
Upvotes: 1
Reputation: 2690
This might not limit the checking you need to do, but it moves the logic from the Activity into the ViewModel (where it can be easier tested).
In your ViewModel
val user: LiveData<Result<User>> = repository.getUser() // put your actual source of fetching the user here
val needsRedirectToLogin: LiveData<Boolean> = Transformations.map(user) { response ->
response.code == 401
}
Improvement: You could create an extension function for this, you can reuse in other ViewModels for the same scenario:
/**
* Returns true when [code] matches the Response code.
*/
fun LiveData<Response<Any>>.isErrorCode(code: Int): LiveData<Boolean> = Transformations.map(this) { response ->
response.code == code
}
And then use it like:
val needsRedirectToLogin: LiveData<Boolean> = user.isErrorCode(401)
In your Fragment:
viewModel.needsRedirectToLogin.observe(viewLifecycleOwner, { redirectToLoginPage ->
if (redirectToLoginPage) {
// do the redirect here.
}
The next step could be having an EventBus, or BroadcastReceiver you could send this event. So that you have only one place to handle this.
There are lots of ways how to go from here (depending on your requirements). But I hope this gives you an idea and will help you.
Upvotes: 1
Reputation: 165
Make a Base class , Create a class which extends the AppCompactActivity means the base class will be a Parent activity and listen for the user.observe there and extends your current activity with the parent activity :
class parentActivity extends AppCompactActivity() {
onCreate(){
////Listener for the observer here
this.user.obser{
}
}
}
//////////////////////////
class yourActivity extends parentActivity(){
//TODO your code
}
Upvotes: 1