How to get Viewmodel instance inside Retrofit object implemented using Hilt [Kotlin] - android

How can I get viewmodel instance inside Retrofit object. Currently I am using Hilt DI and to create a view model instance inside fragment/activity I simply use something like :
private val viewModel : MyViewModel by viewModels()
Now I need to make a call to api from Retrofit object, observe that response and then make an another call from there only.
I have two questions:
Is it possible to get the view model instance inside retrofit object?
Is it the right approach to make network request directly from retrofit object and if not what are the other approaches.
I need to check the network response to read the access token and send a request if it has been expired need to make request to server to create a new token and add it to header of the request. So I feel like it has to be done in Retrofit object.
If any code is required for reference please let me know.

Related

How to make a single method for calling api and pass the respective pojo class to retrofit call?

How to make a single method for calling api and pass the respective pojo class to retrofit call?
Retrofit2 callback
But for every other request i need to make different pojo and write same code for retrofit call.I want to make a single method for calling api and pass the respective pojo class to retrofit call

Kotlin extension function with request to rest server

I'm setting up extension function for Timber. I want to have kind of function to send log to my server.
The problem for me is Dagger. I have instance of RestService class in dagger and I'm using it in my whole app.
But to use it I need inject somewhere this RestService. I can't do it in constructor because I haven't it.
I want to have something like this:
fun Timber.serverLogDebug(log: String) {
restService.log(log)
}
Is it probably at all? It will be convenience for me to use my mechanism like simple Timber.d().
Alternatively I can call
restService.log(log)
in every place. But I have to have this instance everywhere.
In the file where you define the extension function, also define a "singleton" object to hold your restService instance, create a setter for it, and reference it from the logger function.
private object ServiceHolder {
var restService: RestService
}
fun Timber.setRestService(restService: RestService) {
ServiceHolder.restService = restService
}
fun Timber.serverLogDebug(log: String) {
ServiceHolder.restService.log(log)
}
Now you can "statically inject" your service instance by calling Timber.setRestService where you plant your Timber DebugTree.
Note: If you want to log to the server every time you log (or every time you log an event of a specific level), you might be better off creating a custom Timber.Tree.

LiveData or DataBinding Observer

I using MVVM on my Android application, on ViewModel I have many observers (from data binding) like ObservableBoolean, ObservableField, I read that I can use LiveData/MutableLiveData instead this observers... What's the difference? I can replace all my data binding observers by LiveData/MutableLiveData?
eg:
replace:
val loading: ObservableBoolean = ObservableBoolean()
By:
val loading: MutableLiveData<Boolean> = MutableLiveData()
Many times has passed and I learned a lot...
Replace all Data Binding Observable by LiveData, because LiveData respect the Activity lifecycle and can be used in JetPack lib's, like Room, Coroutine...
Depends on where you are reading the data from .
In our current project ,we read directly from RoomDB . RoomDB has the capability to send back a liveData object .
Through your ViewModel , you do a query to RoomDB which returns a LiveData (RoomDB will be your Single Source of Truth)
Your View say an Activity or Fragment - Subscribes to this viewmodel as an observer
And you update the view as per the response returned .
You could also directly bind the xml through Android Databinding(Using LiveData with Data Binding)
Mutable Data is used normally if you have any modifications after retrieving
This is a good Place to Start
If your aim is to just change basic properties of views in xml based on a change with the data in primitive data type in view model, it is simple and easy to use Data binding. For rest of the cases, live data is the only way.

How to use ViewModel in Android with LiveData from repository (DB/network)?

I have Fragment/Activity that needs to display some data.
The data are coming from web API (or can come from DB).
I have Repository class that exposes this data as LiveData making request to web API or DB.
Now, I need to implement ViewModel with LiveData and consider how I should do this correctly. I have try to resemble this example:
https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/ui/repo/RepoViewModel.kt
But this example is very specific. As I understand it I have:
repoId -> which I need to set from VIEW using setId() at the start
of Activity/Fragment
then I can refresh data in view model's LiveData using retry() which only resets repoId with the same value
repo, contributions - real observable LiveData are making request by repository to Web API each time repoId is set using
Transofrmations.switchMap()
So: In Activity I need to:
viewModel.repo.observe(), viewModel.contributions.observe()
viewModel.setId() - to get initial data loading
viewModel.retry() - each time I want to refresh data in VIEW
Now in my Activity I need to display First Name/Last Name in Navigation Drawer.
1. I need to load this data on Activity create
2. I need to refresh this data each time Drawer is opened or maybe on Activity Restart (from background)
3. I have UserProfileRepository.getUserProfile() -> returning LiveData
Here is my problem! this request to web api doesn't need any ID as it just takes user profile based on current authentication token in header (this is passed to HTTP request headers using interceptor)
So I don't have any repoId or userId (in my case) to make it MutableLiveData and then make other properties on view model using Transformations.switchMap.
I have tried to directly return LiveData with:
fun getUserProfile() : LiveData<UserProfile> {
return repository.getUserProfile()
}
But here was problem with refreshing View as future calls to getUserProfile() just returns new Observable LiveData, instead notifying previous LiveData observer.
I think I could use some MediatorLiveData and local LiveData property in ViewModel but this seems a little overcomplicated.
So I conceived such approach (using fake refresher private property of type LiveData<Int>). It function as a trigger for Transformations.switchMap() blocks to execute each time I want to refresh userProfile (or enforce repository to make web api request, return new LiveData<T> and as I understand place this new data in ViewModel property userProfile live data. This way my Activity's Observer will be notified with actual web api data each time I call refresh() method.
class UserProfileViewModel
#Inject constructor(private val userProfileRepo: UserProfileRepository) : ViewModel() {
private val refresher : MutableLiveData<Int> = MutableLiveData()
val userProfile : LiveData<Resource<UserProfile>> = Transformations.switchMap(refresher) { refreshCount ->
userProfileRepo.getUserProfile()
}
fun refresh() {
refresher.value = (refresher.value ?: 0) + 1
}
}
Is this approach correct way to solve this problem? Or should I implement it in other way.

Having trouble to implement repository layer in android with retrofit and rxandroid

I started to use rxandroid yesterday and trying to make repository layer for api with retrofit and rxandroid. However, I realized that I cannot easily return result from repository to activity or fragment.
With request result I need to make grid adapter and set it to view.
Since I cannot have application context in repository(I think it shouldnt). I came up with idea that pass observable back to presenter.. Is is good practice or Observable object should not be passed around.
Repository code
Using passed Observable (Observable will be move to presenter later)

Categories

Resources