Who knows about programming for iOS and data source/delegate paradigm will understand me.
The best practice for implementing custom view in iOS:
Implement MyView class inherited from UIView
MyView has dataSource field.
On drawRect: method MyView asks dataSource for items to draw.
dataSource object conforms to required protocol and implements needed methods.
It is very similar how is implemented UITableView, but I am not talking right now about cells.
Could you please let me know the best practices to implement custom view (like MyView) in Android with MVC pattern?
See MVC pattern on Android
Read all the answers to get a rounded view of android patterns as I don't find the first one very helpful.
Design decisions have been made regarding fundamental application components which prevent pure MVC being implemented, for example the use of activities which don't allow decoupling of the layers.
I find viewing android apps in a MVC way confuses matters as you end up misusing components like activities and adapters by trying to adapt them to perform a function they weren't really designed to do.
UPDATE
You need to make the question a little more specific to get a good answer, provide details of what sort of view you require (list, grid, simple) and what sort of models you are using (where are they persisted etc).
Although it's fairly subjective I have found the following when programming with Android:
Models tend to end up being unavoidably dumb (the anemic anti-pattern). This can be because in many occasions you will find the adapter is passed content to present in the view in the form of an object or collection and then operations on those objects or collections should be performed through the adapter so the adapter is aware of when they are changed and can manage the view accordingly.
The adapter can be treated as a link between model and view, a controller if you like but without many of the advantages of a pure MVC controller. I have found that customising the adapter can be effective (although you end up with 'fat controllers' if you are viewing it from an MVC perspective). Any UI input which would invoke changes to the content can then be called by adapter methods which will edit the models using add/remove for lists, or cursor operations for the database etc.
To implement a custom view in Android, you should derive from an existing View, then override the methods you need, which will often include onDraw(), onMeasure(), and probably one or more event handlers1.
To implement something in the spirit of MVC, the data that your component represents should not be in the view class itself but instead in other classes. The exact design is up to you: you can have data stored in files, in Java objects, pull it from a Content Provider2, etc.
When drawing (override onDraw()), you should look at the state of your data and draw accordingly;
When handling an event that alters the data, alter the data in the model and call invalidate() on the view to request that it be redraw to reflect the changes.
Related
I am trying to set up all my lists with Room Persistance Library and Paging Library but I am facing some problems when implementing PagedListAdapter.
Question 1
I don't want to write any if, when... conditions in the onBindViewHolder so the scrolling is completely fluid. I have a model with its attributes. As an example, I want to set the visibility of a view that it is inside the layout (like a TextView) depending on a Boolean of the model, but I don't want to use an if. What would be the correct way of achieving that?
Should I create an Int attribute in the model which has the View.VISIBLE or View.GONE? But then the model can get very complex with lots of attributes and all of them are on all the model objects of the Room database.
Should I create another model which only has the attributes needed for the adapter UI? But then every time the real model is modified, I also have to modify the adapter model in order to see changes on the UI. And I think that's not good at all.
Do you know if there is somewhere where I can do this asynchronously in PagedListAdapter?
Question 2
I need to use functions like getString(R.string.resource), which requires a context. I also need to use Glide to load an image into an ImageView, but it requires an Activity context or Fragment context. I tried to inject it using dagger but that's not possible. It is safe to pass that context through the constructor? Or what is the best way of doing that?
(I suppose the same problem happens implementing RecyclerViewAdapter)
In my studied application I have table which save the current player state. This table I use in multiselect queries, so when I change this table, Paging library will change my DataSource. Example app.
I use Context instance from View instance with method View.getContext().
I am actually developing an Android application on which I should display dynamic forms based on metadata contained inside JSON documents. Basically the way it works (without the details) is that a JSON document represent the structure of a form:
{
"fields": [
{
"name": "fieldA",
"type": "STRING",
"minCharacters": 10,
"maxCharacters": 100
},
{
"name": "fieldB",
"type": "INTEGER",
"min": 10,
"max": 100
},
{
"name": "fieldC",
"type": "BOOLEAN_CHECKBOX",
"defaultValue": true
}
...
],
"name": "Form A"
}
What I'm doing actually when the application receive one of those JSON documents is that it loop through each fields and parse it to the appropriate view (EditText, Checkbox, custom view, etc.), adding a tag to the view (to be able to retrieve it easily) and add the view to a LinearLayout. Here is a pseudo-code of how it is working actually:
//Add form title
linearLayout.addView(new TextView(form.name));
//Add form fields
for(Field field: form.fields) {
View view;
switch(field.type){
case STRING: view = new EditText();
...
}
view.setTag(field.id);
linearLayout.addView(view);
}
The issue with this is that with large forms (like >20 fields), it need to inflate lot of views and the UI thread suffer a lot. Another point to take into account is that a single screen may have multiple forms (one after another vertically sorted).
To avoid overloading the UI thread I thought of 2 possible solutions:
Using a RecyclerView.
Using Litho by Facebook.
But multiple questions comes to me when considering these 2 solutions:
Is it a good use case to use Litho? Or using a RecyclerView is enough?
What about the state of my views? If I use a Recycling pattern, would I be able to keep the state of each of my fields (even those off-screen) and so being able to save the form without losing data?
If I use a Recycling pattern to display one form, how would I handle multiple forms? Can we have nested RecyclerView? Forms need to be displayed one after another like inside a vertical RV but if forms themselves are RV, how should I handle this?
This is more a "good practice" question and giving the right way or one of the right way of achieving my goal than a need of a specific answer with code example, etc.
Thank's in advance for your time.
When architecting for the mobile application I would like to address the following questions:
Is it a good use case to use Litho? Or using a RecyclerView is enough?
Are the views are being recycled properly:
What does it mean to us is consider, creating 40-50 view per screen and as user moves out of the view, system should not mark all views for GC rather it should be inside some kind archived list and as we require it again we should be able to fetch from it.
Why do we need to that: GC is the costliest operation which would cause app rendering to be jitter, we try to minimize the GC to called at this point by not clearing the views
For this I would like to go with litho, justification is here as your requirement seems to have more of variable count of viewtypesreference
Conclusion: Litho +1, RecyclerView +0
What about the state of my views? If I use a Recycling pattern, would I be able to keep the state of each of my fields (even those off-screen) and so being able to save the form without losing data?
Saving EditText content in RecyclerView This is one the component but same logic should be appliced to checkbox or radiobutton as well. or as in state-maintenance for litho is here
Conclusion: Litho +1, RecyclerView +1 both has specific API's to achieve state maintenance
If I use a Recycling pattern to display one form, how would I handle multiple forms? Can we have nested RecyclerView? Forms need to be displayed one after another like inside a vertical RV but if forms themselves are RV, how should I handle this?
This has to be addressed with user experience plus technical capability: As per user behaviour IMHO,I discourage the nested vertical scroll however others were able to achieve it you can easily find on how to in SO. Optimal solution would be to have horizontal scroll within either Andriod's or litho's recycler view as here
NOTE: If you need to know implementation details, please raise it as separate question, I would be happy to help there
UPDATE #1:
The issue with this is that with large forms (like >20 fields), it need to inflate lot of views and the UI thread suffer a lot.
UI creation/layout has to be performed at the backend only adding to the view has to be done on UI thread. And litho does it in-built. However same can be achieved native recycler view as well but you have to move off the UI thread and post periodically to UI.
Ok, you have two separate problems here. One is overwork the UI thread, and the other is to keep the state of your anonymous views. About the first part:
1.-Litho could help you with this. But you have to move all your logic towards litho components instead of android widgets. Since I don't know your codebase, I don't know how hard this can be. A recyclerview would help with view recycling, but that only matters if you are well, using a list.
2.-It could, as long as you have a way to keep a representation of the widget's state that you can pass to the adapter and then back to the view (I'm assuming you generate all the windows by code and then have zero reference to them) and so. It sounds messy, and it is messy, so I won't try it.
3.-You can, but is messy. Best approach in this case would be having horizontal recyclerviews inside a vertical recyclerview. Nesting recyclerviews inside another recyclerview with the same direction creates funny problems, like "Why this cell is not scrolling". I would avoid using the recyclerview as a parent if the view does not need it.
Now, to the solutions:
A) UI Overloading: According to your pseudocode, you aren't inflating stuff. You are creating java objects which happens to be subclasses of View. That's good, because creating objects in a background thread is far easier than inflating (Parsing XML and use it as arguments to generate identical copies of a given resource by invoking constructors) stuff in a background thread. While a LinearLayout context constructor requires an UI thread to be executed, other things, like textviews, don't. So you can create the latter ones inside an asynctask and after you are done generating your whole hierarchy, execute the methods that need the UI thread and add the generated layout to the window. For the view classes that don't support being created as java objects asynchronously, you can have an XML file with just that component, like the linearLayout, and create then asynchronously with the support package asyncLayoutInflater. this solution can be implemented in any codebase and would allow you to make your UI generation completely asynchronous.
B)Keeping track of the view state: Again, I'm assuming your view hierarchy is anonymous. If so, what you need is to generate an interface you can use as a contract to invoke both state saving and state loading from a lifecycle aware component, like the activity. After creating such interface, subclass the widgets and create a subscription/event bus system in each widget that saves/loads the state from the widget every time is triggered. That way, each of of the components on the screen would be able to remember their state while remaining anonymous.
Just use the RecyclerView and create views on runtime (you are not inflating, you are instantiating)
Dynamically creating and adding views should not slow the UI thread considerably on mid-range devices. If it does, do investigate for bottlenecks elsewhere
You can perform a simple benchmark by adding/removing/setting text with lots of views dynamically inside a RecyclerView or even a LinearLayout hosted by a ScrollView, and you'll see it goes smooth
Use jetpack composer provided by android
https://developer.android.com/jetpack/compose
I've been looking at creating a stylistically different list view, like many other people, and I started by looking to extend AbsListView. Per the Android doc, AbsListView is:
Base class that can be used to implement virtualized lists of items. A list does not have a spatial definition here. For instance, subclases of this class can display the content of the list in a grid, in a carousel, as stack, etc.
After some effort and review of the ListView implementation, it looks like it may not be possible to extend AbsListView the way ListView does because of the coupling of the two classes and the inability to access certain package members. I stumbled on this form Romain Guy:
AbsListView and AbsSpinner are designed to be extended within the
framework. They could also be extended in 3rd party apps but we did
not expose all the necessary protected fields and methods on purpose.
We want to be very careful in how we expose such APIs so as to not get
stuff for future extensions and internal changes. Our current
recommendation is you simply copy/paste the code you need inside your
app.
I started trying to do this but copying AbsListView becomes a rabbit hole of copying in a bunch of other stuff and it really just seems like a losing proposition. I wanted to see if anyone has had success extending AbsListView who could share a methodology.
[1] http://developer.android.com/reference/android/widget/AbsListView.html
[2] https://groups.google.com/forum/?fromgroups#!topic/android-developers/UhbR1tpVvF0
The post is circa 2010, but his assessment still holds true today. Certain necessary methods & fields are protected, in order to prevent future incompatibilities that could result from changing the internals of AbsListView.
The best solution is still to copy the code for AbsListView into your project, along with necessary dependencies (the rabbit hole you mentioned).
In the meantime, if you want to describe what kind of View you're trying to build, we might be able to point you in a direction that's slightly easier than creating your own AbsListView?
I've had the same experience trying to subclass ListView and AbsListView to develop a 2D scrollable spreadsheet. I ended up with my own subclass of ViewGroup which handles layout and a subclass of TwoDScrollView to handle the scrolling. The hardest parts are getting flings to work correctly (ie. create and place new views before they scroll into view) and synchronizing view positions between scrollable components. With enough time though, it is possible to create a robust component that pulls data from a Cursor and scrolls it around quite smoothly and quickly.
In my current application, which is for in-car use, I am displaying a series of Views (which represent gauges) at arbitrary locations within a RelativeLayout (the dashboard). There is obviously an amount of backing data that describes the positioning of those gauges, their attributes, the measurement data that they display, and so forth.
At this point, it would seem sensible for me to create a separate adapter class to contain the code that translates the backing data into the appropriate gauge Views. This would follow the existing Android pattern doing things, whereby various types of View (ListView, Spinner, etc.) accept an appropriate subclass of BaseAdapter to take care of interfacing to the backing data.
What I was considering doing is extending RelativeLayout so that it accepts an Adapter and calls the standard Adapter methods (like getCount(), getView(), and so forth). My custom Adapter would apply appropriate LayoutParams to each View so that it is appropriately positioned in the RelativeLayout.
So, rather than being a specific question as such, I'm just curious to know whether using the Adapter interface is suitable in this instance. What bugs me slightly is that in the Android library, Adapters seem to be commonly used for Views that present information in a list format. Do you think that subclassing Adapter (or BaseAdapter) sounds like a good pattern for what I'm doing, or is it going against the grain somewhat by using it in a situation where data isn't being presented in a list?
I'm just curious to know whether using the Adapter interface is suitable in this instance
IMHO, no, unless you have an arbitrary number of gauges. AdapterView is designed around supporting 0-N children using a recycling pattern to only require a few actual children. Adapter is designed around being used with AdapterView.
I'm somewhat new to Android and am in the process of designing an application with a couple fairly complex views. One of the views is intended to involve a complex view displaying information associated with model objects and segregated into several different views; the navigation of which is meant to be achieved using sliding effects (i.e. sliding one's finger across the screen to traverse from one screen to the next, etc). The view itself will be used to host multiple sets of views for varying types of model objects, but with a general structure that is reused between them all. As a rough example, the view might come up to display information about a person (the model object), displaying several details views: a view for general information, a view displaying a list of hobbies, and a view displaying a list of other individuals associated with their social network. The same general view, when given a model object representing a particular car would give several different views: A general view with details, A view containing photo images for that vehicle, a view representing locations which it could be purchased from, and a view providing a list of related cars. (NOTE: This is not the real data involved, but is representative of the general intent for the view). The subviews will NOT cover the entire screen real-estate and other features within the view should be both visible and able to be interacted with by the user.
The idea here is that there is a general view structure that is reusable and which will manage a set of subviews dynamically generated based upon the type of model object handed to the view.
I'm trying to determine the appropriate way to leverage the Android framework in order to best achieve this without violating the integrity of the framework. Basically, I'm trying to determine how to componentize this larger view into reusable units (i.e. general view, model-specific sub-view controllers, and individual detail views). To be more specific, I'm trying to determine if this view is best designed as a composite of several custom View classes or a composite of several Activity classes. I've seen several examples of custom composite views, but they typically are used to compose simple views without complex controllers and without attention to the general Activity lifecycle (i.e. storing and retrieving data related to the model objects, as appropriate). On the other hand, the only real example I've seen regarding a view comprised of a composite of Activities is the TabActivity itself, and that isn't customizable in the fashion that would be necessary for this.
Does anyone have any suggestions as to the appropriate way to structure my view to achieve the application framework I'm looking for? Views? Activities? Something else?
Any guidance would be appreciated. Thanks in advance.
I'm trying to determine the
appropriate way to leverage the
Android framework in order to best
achieve this without violating the
integrity of the framework.
Phones have very limited RAM and very limited CPUs. Your average Android device has the power of a decade-old PC, or worse. Please do not over-engineer your application.
To be more specific, I'm trying to
determine if this view is best
designed as a composite of several
custom View classes or a composite of
several Activity classes.
I'd argue "none of the above". If you are aiming to make "custom View classes" for distribution to the Android developer community at large, that's one thing. For your circumstance, though, just build your Views -- don't subclass them. I am definitely of the "composition over inheritance" mindset when it comes to Android's View system.
IMHO, Activity is your controller (or perhaps presenter, a la MVP, is the better architectural analogy), layout XML and their constituent Views are the view layer, and your database is your model.
I'm not sure that I followed all that you were saying there, a diagram showing the flow might help, but..
You generally can only have one Activity visible at a time. That activity is responsible for rendering the entire view. The only exception to that that I have seen is a pop-up, alert style window. In my experience those tend to be a bit slow though. Typically you have a new activity every time you change pages. It sounds like in your case it might be every time the general view changes.
You can, however, easily have a few layouts that are reused in various activities. Layouts are composable, so you can, for example, have one layout for your detail layout that gets included in the main layout.