ViewModel without reference to View with Camera 2 - android

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).

Related

Android MVVM UI control

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}"

Dagger 2 - Right way to pass parameters to Fragment

In my previous projects, I was instantiating my Fragments with Android's build-in method newInstance(param: Type) so I wouldn't lose params even Android recreates the Fragment. Now, that I'm migrating to Dagger, legal way to instantiate Fragments is either #Inject'ed params or empty constructor (as far as I know). I'm left with two option in my mind which are either to create a custom annotation for each param (cumbersome) or use #Named, both looks quite overkill considering 15-20 different purpose Fragments with each requiring 3-4 different Type params. I would be happy to hear suggestions or just kinda assertion that those are my only options

Android Best Pratice to reuse code and layout

I've been reading about the include tag on xml, fragments to use on layout for smartphone and tablets but I'm getting more confused than getting a solution to my problem.
My App has 4 screens.
1 - You login and it download info from a json
2,3,4 - From login, Activity 2 load (A list with custom adapter), where you can click one of 2 images to jump to 3rd and 4th activity.
I need now to create the activity 1, 2, and 3 again with different JSONs being parsed, with 1 and 2 having the same layout of the existent ones and 3 with a different layout.
The code I need for them to work is(or can be) the same (Download Task with AsyncTask, button click listeners, etc) I already have for those activities.
I think it's not a goot pratice to copy basically the same getView method, for example, and paste on a new class, right? The buttons wouldn't work on the second range of screens for example.
So, what approach should I take that isn't copy and paste code and change things manually?
Sorry for the newbie question.
If needed I can provide code.
PS 1: I've already did tests with include on xml and copy code but that doesnt look professional
PS 2: Is fragments only for different screens like tablet or I could make something with it?
That's several questions, so here's several answers, including to some un-asked questions:
To the greatest extent possible, strive to remove as much code as possible from your Activities, Fragments, etc. If it doesn't have anything to do with the Android lifecycle or actually putting something on the screen (e.g. parsing JSON), put it in a "plain old java" class. Also, this way, you can share the functionality among Activities.
IMHO, you should never use an AsyncTask, for any reason. They're used with an Activity or Fragment, but don't respect the Fragment or Activity lifecycle, so are often the cause of crashes that can be difficult to diagnose. Use something synchronized with the lifecycle, like a Loader. Or go the RxJava route, where Subscribers can be canceled at the appropriate point in the Activity/Fragment lifecycle.
Fragments can be good for code re-use, but they have a slightly different lifecycle from Activities, so they can be difficult to work with, so use them sparingly and be careful. If you're doing it just to re-use a bit of UI (but not behavior), a layout "include" is probably better. For behavior, a custom View class can be a good alternative to a Fragment.
Don't do HTTP / REST access yourself, using primitives like HTTPUrlConnection. There are a lot of corner cases that are going to get you into trouble. Use one of the several really good open-source libraries that are built for this purpose. I highly recommend Retrofit.

Tips on refactoring an Android prototype

I have an Android project I've inherited from another developer.
The original code was hacked together using a single View and a single Activity. The view class has a State variable that is switched on during input and rendering.
Each "screen" is a single bitmap rendered directly onto the screen. There are no layouts used at all. To make things even worse each variable in both the View and Activity classes were all declared public static and would access each other frequently.
I've reworked the code so it is now somewhat manageable, but it's still in those original two classes. This is my first decently sized Android app so I'm not completely sure where to go next.
From the looks of things, each "screen" should have its own View and Activity. Is this the general practice?
If so I need some way to share data between the separate Activities. I've read suggestions to use a Singleton class that holds generic data. Is there any other ways that are more built into the Android framework?
Thanks in advance.
I would recommend using one activity per screen, or rather, per function. An activity generally has one associated view that draws the UI. If all the activity does is display different bitmaps, than you can define an ImageView in the layout and display the various bitmaps in that ImageView.
Using public static fields is bad practice in Android Activities. Activities should not access fields in other Activities at all, they should pass data to one another through the intent, or via a database, or via shared #Injected classes.
From what you write, it may be easier to start that app again from scratch, than to try to fix the current app. I have been there, done that, afterwards regretting not scrapping the app and starting from scratch.

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