Android MVVM UI control - android

I'm started to learn MVVM with LiveData on Android. I think displaying and updating basic data is clear to me. The topic I struggle to find a best practice for is controling the UI.
Let's say I have a basic UI, a form for example. It has a few EditTextViews to input data. At the end it also has a switch. If it is ON a few more EditTextViews are shown to fill in. When it's OFF of course they are gone.
My question is where to implement this logic?
In the Activity/Fragment code? Then business logic would be involved in the VIEW part of MVVM (which I don't find great).
In the ViewModel? Then business logic would exist in a, let's say, data cache. This way I would have to create a bunch of boolean getters in the ViewModel which compute the values for separate View visibilities. Then in my Activity in the subscription block for LiveData change I need to read all of these values and set visibility for the views one-by-one.
In a separate Service/Helper/Util class? It would be the same solution as #2 just the logic extracted from the ViewModel.
What is the best practice here? Same question can come up with the topic of user input validation though (and I guess there are a number of these areas).

I'd go with the 2nd approach, but slightly different implenetation (using DataBinding), inspired by Google's sample Sunflower app:
https://github.com/android/sunflower
It's supposed to be introducing Jetpack best practices, including MVVM.
Then in my Activity in the subscription block for LiveData change I need to read all of these values and set visibility for the views one-by-one.
Instead of doing that you can subscribe your layout to the viewmodel (with DataBinding), similar to this:
https://github.com/android/sunflower/blob/master/app/src/main/res/layout/fragment_plant_detail.xml
<data>
<import type="com.google.samples.apps.sunflower.data.Plant"/>
<variable
name="viewModel"
type="com.google.samples.apps.sunflower.viewmodels.PlantDetailViewModel" />
</data>
and then use set the visibility based on the references to the viewmodel without getters, in the layout itself
app:isGone="#{!viewModel.isUnderAge}"
or
android:visibility="#{viewModel.isUnderAge? View.VISIBLE : View.INVISIBLE}"

Related

State in Android Compose vs XML / imperative framework

I am going through the Compose pathway and I keep seeing all of this emphasis on state hoisting. Is this in some way more relevant in the new Compose framework as compared to the old paradigm? It seems like it is just a good programming technique in general. I am worried I am missing a particular advantage in the Composable system.
From the perspective of an Activity or a Fragment they are nearly identical. A stream of states come in and the Activity or Fragment needs to react to the changes by updating its content.
In Compose, however, the composables are themselves tiny fragments of UI all the way down, so to speak. In Compose you can arbitrarily break a UI into smaller and smaller pieces that each react to state changes. It is in this decomposition (so to speak) that state hoisting becomes important and allows these smaller UI pieces to be reusable. Even when you use a Text or a Button they are just composable functions that layout and draw text or map user input to click events, etc.
If state is already in the UI model then it is already hoisted. No additional hoisting is necessary. State hoisting is only important if the composable has its own model of information. The TextField, for example, takes its state as a parameter instead of creating and holding it internally. This allows the state to be held directly in the UI model instead of needing to be synchronized with it. The model can decide if an when the state changes, the TextField just requests the state to change, it doesn't control it. Traditionally, a TextField would have it own internal model of the text and just send out onChange notifications when the value changed. This means there are at least two models of the value of the field, one held by the control and one held by the application model. Synchronizing these can be tricky.
Allowing hoisting of composable state allows there to be a single source of truth, the application model, instead of several states all needing to be synchronized to a single value. Compose does not dictate what the model is or how it is stored, it just needs to know when the value changes so it knows when to update the UI.

Should similar screens be different Fragments?

Ok so I'm creating an app. I have a "Creation" page, and a "Detail" page for the same item. The UI is the same, probably the logic will be the same as well, only difference i can think of now is that when creating, the Object backing my UI is local, and as an argument in the fragment I get the item "Name", when showing the detail, the argument is the item's "ID" and the data backing my UI is remote.
My question is, following clean architecture and all around good programming rules, is it better to separate this screen in 2 almost identical Fragments, separating concerns and allowing for future differentiations, also possibly avoiding a "god fragment" but having a lot of possible code duplication, or is it better to keep them in the same screen, avoiding code duplication?
From my experience, you should avoid code duplication as much as you can. I don't know how deep and complex is your app, but if you have two almost identical fragments, I would use a 'ParentFragment' that contains the common code, and extend your Fragments from it. This way you can customize both fragments in the future, while maintaining the common features.

ViewModel without reference to View with Camera 2

In MVVM, a ViewModel must never reference a view. But how achieve it for use of Camera 2 API?
For Camera setup, there are TextureView parameters needed (for example TextureView.surfaceTexture, TextureView.isAvailable, TextureView.width).
I'm trying to put logic from Camera2Basic example to a ViewModel.
Is it clean solution to pass needed values by custom cameraInit(...) function or is it better to keep that code in the fragment?
In general as part of MVVM the ViewModel is the component between your view (Fragment) and the model (some file manager in your case to save the image to a file). As you already mentioned, best practice for ViewModel is not to know anything about views. Considering this the ViewModel should accept some data from the view (the bitmap for example) and pass it to the model. You can achieve this by handling all the view dependent code in your Fragment (or some helper class handling the camera if you want to keep your Fragment as clean as possible) and pass it to the ViewModel.
The main aim of doing it this way is the possibility to test your ViewModels with simple Unit tests without the need of instrumentation. It is always important to know that using architectures like MVVM or MVP will NOT reduce the complexity of you code, in general the complexity will be even increased since you have the same logic plus overhead of the architecture. Because of this fact you always have to consider if it is worth to apply MVVM (it wont help much if you don't want to test your code anyway and the classes are not to large anyway).

How can I dynamically create an Android Preference?

A mockup is below that probably explains better than words. Essentially, I want a list where items can be added/removed dynamically by the user, and each item has configurable settings screen.
So there are two keys here:
Adding to the main preferences screen
Starting an
activityForResult when an item is pressed. This activity will show
another preferences view (sliders, checkboxes, etc) where the user
can manipulate these and then return the new values to be stored in
a data structure.
Image:
I would suggest heading down the road of Fragments - specifically PreferenceFragment: http://developer.android.com/reference/android/preference/PreferenceFragment.html
Why I think this will work well for you:
Furthermore, the preferences shown will follow the visual style of
system preferences. It is easy to create a hierarchy of preferences
(that can be shown on multiple screens) via XML. For these reasons, it
is recommended to use this fragment (as a superclass) to deal with
preferences in applications.
Your question is a little bit vague, but probably this is best solved by storing the user's data in a database (and using standard CursorAdapter and CursorLoader instances to show this data to the user) rather than trying to force everything into the Preferences framework. The CursorAdapter is optimized for dealing with arbitrarily large result sets, while PreferenceActivity and friends really work better with a fixed set of data.
The Preferences stuff is designed to be easy to implement for its specific use case, but if your use case falls out of that scope — and it sounds like it does — it's going to be a hassle to squeeze your data into a preferences model.
If you just like the Preferences UI, you can of course peek at the Android source code to see how it is implemented while still letting your own logic drive a variant of that UI.
Actually creating the preference screens dynamically is easy. You can do it in code (search the API Demos sample app for PreferenceFromCode.java) or by expanding an XML file that you can write (PreferencesFromXml.java). What's going to be hard is coming up with a sensible UI and storage back-end for the user to compose and store these dynamic preference collections.

Does Android UI development lend itself well to a particiular design pattern?

Does the Android platform lend itself well to a particular style of UI programming like MVC or MVP? Most of my UI experience is with spaghetti code on a very old embedded device or in GWT with MVP so I do not know where to start.
The MVC Pattern is more or less pre build into android.
You have three layers consisting of:
The Model Your data classes, Content providers etc. wrapping all your data.
The Controllers Treat all your activities as controller classes. Don't do anything in them that looks like business logic or data persitance. Just react to events from the model or the user and forward them to the correct layer.
The View Often the Activities are called the view because there it is the java code that is closest to the views. But in my opinion the view layer in Android is mostly defined in xml. You define your buttons, images, state changes etc in xml and then connect it with your application through your Activities.
There are some simple rules to follow to have a basic separation of this layers.
Define as much of your UI in xml only
instantiate Views yourself if there
is no other way to achieve something,
don't change the graphical state of
views from code, for example don't
change the background of a button if
the button is deactivated, or the
color of a font if a button was
clicked, do all this through stateful
drawables, and selectors in xml.
Don't do any data saving or logic in
your activity classes. Call to extra
model classes for this purpose. This
will make your activities clean and
short
If you want to change your data think
about going through a full
controller changes model -> model
informs controller about changes
-> controller changes UI cycle instead of having the controller
change the model and the UI
directly because other observers
of the modes may not be notified.
I do not know if the Android lends itself well to a specific design pattern when it comes to UI development per se, you can certainly use a particular pattern if it helps.
When in doubt you can check out the standard User Interface Guidelines and see what the guidelines are for particular interactions.

Categories

Resources