I was wondering whether android binding is compatible with live data on conceptual level.
There is a simple task: call server after button is clicked.
So in my view I have
android:onClick="#{viewmodel::onOrderButtonClick}"
and proper onOrderButtonClick(View) method is defined in ViewModel.
But in order to make server call via LiveData I need my Fragment reference (observe() method needs LifecycleOwner instance as first parameter).
Of course I cannot hold reference to fragment in my ViewModel.
What is the pattern here? Do I really need to implement all event methods in the fragment class and delegate them back into view model class?
After some digging there is a bad news and a good one.
The bad news is that the fragment has to be used anyway (there is always some code in the fragment for each livedata event)
The good one is that it can be done relatively clean:
Call getOrderObservable() from fragment to view model. It returns
MutableLiveData<> created in view model's ctor.
Then call observe() on that observable In view model's onOrderButtonClick()
In onOrderButtonClick() in view model just call setValue()
That solution in my opinion minimalizes amount of code in the fragment. Still it looks not so elegant to separate making the network call and handling the result
Related
I want to pass a LiveData as is to BindingAdapter.
Inside the BindingAdapter I want to do a Transformations.map and display different options the user can select and when clicked send the result back using the same LiveData.
In order to observe the LiveData in the BindingAdapter I need access to the LifecycleOwner, ideally of the fragment view. I need that if I want to call .observe on the liveData or set the LifecycleOwner on the new binding I create inside the BindingAdapter.
Any idea how I can do that?
Firstly, I'd like to recommend you not to go down the road of placing too much of your business logic into your BindingAdapters. Besides it being a good practice to use binders to simply set style attributes, I have personally seen spaghetti-code disasters made by placing too much logic into the adapters. This is a really sketchy practice as the code is run for every element that listens to your binding, every time your livedata changes so your logic can get pretty hectic, very quickly and your app performance can be decreased quite swiftly, too.
Having said that, I don't think you should be passing in LiveData into your binding but instead the Object E that is being held in your livedata. This way you can:
keep your work inside the fragment that both has a LifecycleOwner and is the recommended way to observe for changes
pass into your LiveData instance the result of your Transformation and
display it in your UI by receiving it directly through your binding
This way your adapter has only the logic to display the result/results and all the work is being handled correctly by the fragment.
ViewModel Implementation
If you'd like to take this a step further, following Google's recommended Architecture Components, I'd suggest you to place the logic inside your ViewModel (should you be following the MVVM pattern) and avoid the use of the fragment altogether. You'd place the LiveData variable inside your viewModel (say var itemColor: LiveData<Int> = MutableLiveData<Int>(R.color.colorPrimary)) , connect it to your binding through xml
i.e.
app:showColor="#{viewModel.itemColor}"
and place all the logic of your Transformations inside a function in the viewModel. Setting the value to itemColor would directly send the value to your bindingadapter (showColor) and you could use the value as needed without even touching the fragment or observing the variable!
Note: please remember to set the lifecycleOwner to your binding inside the fragment as so : binding.lifecycleOwner = this, otherwise the adapter will not listen for changes.
I hope this helped, Panos.
I'm getting started to use the mvvm pattern to structure my android application, and I want to maintain its pattern by letting the view to observe data from the viewmodel but in cases where there is need to only observe data when needed or once(such as navigating to a new layout), I find it difficulty to implement this case. Please is it possible? and how exactly can it be done through code(kotlin)?.
I think that it's bad decision, cause your ViewModel shouldn’t know anything about the View and everything from ViewModel should 'push' to View using DataBinding or Observer-Pattern.
The ViewModel is responsible for wrapping the model and preparing
observable data needed by the view. It also provides hooks for the
view to pass events to the model. The ViewModel is not tied to the
view however.
source
Even if you decided to do such things, then you have to understand that it can be difficult to manage subscriptions when view is destroyed.
When you wanna observe something only once, then you have to write your own extensions for LiveData (here you can find example).
Also you can read this article to make sure how to deal with single-events.
If you just ask how to call something from ViewModel, when some concrete event occurs in your View, then the best solution here will be simple call method in ViewModel from your view in listener of widget(button etc)
I work on rewriting my app to MVVM architecture concept.
Based one my understanding all the business logic should live in the ViewModel and the UI components in the Activity or Fragment. I use a third party library that needs to be initialized with some view's like: MyLibrary instance = new MyLibrary ("key" , imageView, surfaceView) and then doing some manipulations on these views.
What would be the best place and the right way doing that knowing that it's not recommended passing any Android view to the ViewModel and also not the right thing to initialize SDK in the Activity
You have already answered your question. It's the other way around, the ViewModel informs the View (activities and fragment) WHAT should be chaged, and the View simply handles HOW it should be updated.
Most of the business logic however, if we want to be nitpcky, should still remain in the model. The ViewModel only holds the LiveData that the View needs. Some reasons for this is that you don't want your model to be Android architecture dependent. But also to follow the single purpose principle. This way you avoid making the ViewModel into a God object that handles everything. Instead you only allow it to format data, pass commands, provide factory methods for binding
to the viewModel, and subscribing/getting relevant changes from the model.
So in short: The View passes user-input to the ViewModel who issues commands on the Model. The ViewModel then format the changes from the Model and posts the changes using LiveData to the View. The View finally updates the components that the user can see.
Check the example here for how the UI is updated.
https://developer.android.com/topic/libraries/architecture/viewmodel
Read more about the pattern here:
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel
I am trying to understand MVP design pattern practically and went through this link and few other links and made some observation. I want to know that all the below observations are correct for implementing MVP design pattern practically?
Activity, Fragments and our xml layouts will be part of View.
Our POJO classes or the classes which are responsible for fetching data, making API calls or calling Web services are part of Model.
We create an interface which contains abstract methods for various events we need to perform on View or various events for the lifecycle of view. Activity/Fragment will implement that interface and pass its reference to Presenter constructor.
Presenter will have reference to both View and Model. Its constructor will contain reference to an interface which Activity implemented and it will create an object of Model.
Whenever an action is performed on View or for any lifecycle callback of View, a method of Presenter is called from View. That method will interact with both Model and View as per requirement. It will call method of Model and will call the method of interface that Activity implemented so both Model and View can perform action in their classes.
Your understanding is mostly correct:
Correct.
Quite correct. Although note that in MVP design pattern terminology the notion Model (M) is pretty general. In practice Model is divided in a few layers depending on their "functionality", e.g. Interactor, Repository, network etc.
In general, correct.
Correct regarding the VP part and incorrect on "it will create an object of Model". Presenter should not create an instance of Model, it should communicate with it via an interface too.
In general, correct. However, View should not care about lifecycle of View. Model should provide data.
I'm creating a sample app (Last-Mvvm) to learn (and possibly show) the usage of mvvm pattern, using Android data binding.
I have an activity with my ViewModel object inside. I have also a RecyclerView adapter, which contains an arraylist of items that are converted to another Viewmodel. I want to save the state of the list inside the adapter (for rotation changes).
So: where should I save it? inside the activity? Or in the viewModel of the activity? Or somewhere else?
Also, there is another thing that isn't really clear.
Is it fine to perform rest calls (through Retrofit) or database calls directly from the viewModel (since i'd use interfaces), or would it be better to make an interface that the view (activity) implements and performs all the calls?
I will try to explain
First. So: where should I save it? inside the activity? Or in the viewModel of the activity? Or somewhere else?
and
Second. Is it fine to perform rest calls (through Retrofit) or database calls directly from the viewModel (since i'd use interfaces), or would it be better to make an interface that the view (activity) implements and performs all the calls?
on example from article.
On the schema below you can see implementation of OnClickListener and OnLongClickListener for RecyclerView item.
doted lines is a links
solid lines is a method calls
How it works
ViewHolderWrapper works as ClickListener for root view of ViewHolder. Depending on implementation ViewHolderWrapper can be proxy for HolderClickObservable or depending on SelectionHelper, ViewHolderWrapper can manually highlight selected item.
SelectionHelper is responsible for saving selection state and notify SelectionObserver about changes.
Listener (Adapter in this case) is responsible for highlighting of selected items and for updates.
Summarizing
First. You can restore adapter state via activity with methods onSaveInstanceState() and onRestoreInstanceState().
Second. You need to create lightweight ViewHolder which only responsible for binding data to view. Actions can be performed at adapter or activity.
See also example application