I am using multiple Livedata ovservers in a fragment like below. It is the best way to do so?
final Observer<String> textLeftObserver = textLeft -> {
//body
};
final Observer<String> textRightObserver = textRight -> {
//body
};
appViewModel.getTextLeft().observe(getViewLifecycleOwner(), textLeftObserver);
appViewModel.getTextRight().observe(getViewLifecycleOwner(), textRightObserver);
You can use multiple observer in a fragment. It is totally fine only if the stream of data is different from each observer.
for example you have one user stream and one order stream It is fine to use two observer here.
But if you are observing two stream one is user's name and user's age. then you can create only one stream with user object and listen to it instead of creating two.
I hope it will help you to understand.
Related
I have two Views, Coffee and Doppio coffee (maybe any coffee). CoffeeView is a list of available coffees, and when one Coffee has taped, it will open its details page (in this example, Doppio has tapped).
I have two ViewModels, CoffeViewModel and CoffeeDetailsViewModel, respectively.
I can implement this scenario but can't MVVMify it. I know about routing. I can pass variables on routing but not between ViewModels. See the below Picture. When I tap on a specific item on Coffee, I want it to send its data from CoffeeViewModel to its CoffeeDetailsViewModel and at the same time open its DetailsViewPage and show data on that page.
await Navigation.PushAsync(new CoffeeDetailsPage(family));
or
await Shell.Current.GoToAsync($"{nameof(CoffeeDetialsPage)}?Data={Data}");
I have used the above routing syntax, but it can post data to CoffeeDetails.XAML.cs not to its ViewModel, and when I want to send data to its ViewModel, it doesn't launch its page.
Update
The ViewModels are instantiated in Xaml using the below syntax.
<ContentPage.BindingContext>
<ViewModel:CoffeeViewModel></ViewModel:CoffeeViewModel>
</ContentPage.BindingContext>
if you assign the VM in the constructor you can easily pass a parameter to it
public CoffeeDetailsPage(Family family)
{
InitializeComponent();
BindingContext = new CoffeeViewModel(family);
}
I have the next segment of code, I would like to add unit test for the next button, one friend say "There is too much to create one live data observer only to test each function" . The problem is that I have at least 10 buttons with deferents actions like intents, calculation, send data, etc. each button do different things, some represents actions, others represent events .
The image is only one of those. but the question is, how to make it testeable , I understand for testing I would need to create a method on the viewModel , and make a LiveData only to return to the view and register the observer in the fragment only to make the intent, for me it sounds like "walk around" . Why should I have an observer only for a Intent, if the view dont needs to "observe" nothing, only to notify to the view to do something.
Its similar for the other 10 buttons. Really I need to create one liveData to be able to test each button ? To have one observer and return immediately to the view only to do those things sounds exaggerated . There is a better way to do it ?
buttonContainer.setOnClickListener {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
val uri: Uri = Uri.fromParts(SCHEME, activity?.packageName, null)
intent.data = uri
startActivity(intent)
}
// Each of those make one action, but to have an observer for each, don't sounds good,
// why whould I need an observer only for one action , but if don't, I couldn't test it
liveDataAction1.value = true
liveDataAction2.value = true
liveDataAction3.value = true
liveDataAction4.value = true
liveDataAction5.value = true
Instead of having multiple LiveDatas you could have one LiveData<Consumable<Event>>.
Consumable is just a pattern for making sure your events are consumed only once (Read this for more information)
Then define your Event as:
sealed class Event {
class OpenDetail(id: Long): Event
object OnSuccess(): Event
....
}
Then in your tests you just verify that calling method x, results in the according Event to be sent out.
Is it possible to observe live data in a view model without creating a new live data? As I understand, one should never .observe in view models as this results in issues with the life cycle. Thus, one usually uses Transformations.switchMap(), but this creates a new live data which I have to assign. Ideally, I would like to do something like this:
val liveData: LiveData<String>
liveData.switchMap {
// Do stuff
}
or
liveData.observe {
// Do stuff
}
You can use observeForever but in that case, you have to take care of disposing it when viewmode clear
Not exactly. The reason why you should not observe something in viewModel is because it's not bound to the correct lifecycle. Best way to do things is to observe your LiveData in view and intercept your data in the ViewModel using a MediatorLiveData and post the processed data directly in the LiveData variable.
I just wanted to know and how to implement multiple API call observer in a single view(Act or Fragment)
So my question brief is I have a multiple API's calls in a single Activity like fetch user detail, fetch banner image list and products list via ViewModel and Livedata,
So is it compulsory to observe three livedata depend on three API calls?
I want to observe only a single livedata for three different APIs.
like below example, I have three live data for three APIs
var userLiveData = MutableLiveData<UserDetails>()
var bannerLiveData = MutableLiveData<BannerDetails>()
var productLiveData = MutableLiveData<Product>()
Call rest API and observe in Act like below
userLiveData.observe(this, Observer { data ->
})
bannerLiveData.observe(this, Observer { data ->
})
productLiveData.observe(this, Observer { data ->
})
it is ok no issue but I think it is not good practice to observe every API call, I need to combine all three API calls to one so is there any solution for that?
I read about MediatorLiveData but cant help!
Forgive me for my bad English.
If anyone knows anything please help me.
I have an activity that performs multiple background tasks, for example:
getJWTToken(), sendFCMTokenToServer(), isPromoAvailable(), isForcedUpgradeRequired(), fetchNewsFromServer(), sendUserLatLngToServer()
These all are network calls, and take some time.
This is what i have done for 1 method.
HomeViewModel homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
homeViewModel.sendFCMTokenToServer().observe(this, isFCMSendToServer -> {
Toast.makeText(this, "Home FCM Observer called", Toast.LENGTH_SHORT).show();
});
Now my question is do i need to repeat the above line homeViewModel.observer(this, ) for each method, or there is some other way for achieving this.
I think, You should not!
You don't need to observe these changes separately.
You can do these:
make ViewState Data model class which contains all these data (jwt token, other booleans and all)
observe ViewModel based on this model from activity.
In ViewModel, you can just change/update these ViewState model values using LiveData.postValue() as well.