Solution for creating dynamic forms with Android

I am actually developing an Android application on which I have to render dynamic forms based on the metadata contained in the JSON documents. Basically the way it works (no details) is that the JSON document is a form structure:

{
    "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 do when the application receives one of these JSON documents is that it looks at all the fields and parses them in the appropriate view (EditText, Checkbox, custom view, etc.), adding a tag to the view (so that get it easy) and add the view to LinearLayout

. Here is pseudocode on how it actually works:

//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 problem is that on large forms (e.g.> 20 fields) there are a lot of views to inflate and the UI flow will suffer a lot. Another point to consider is that one screen can have multiple shapes (vertically sorted one after the other).

To avoid overloading the UI thread, I thought of two possible solutions:

But when considering these two solutions, many questions arise:

  • Is it good to use Litho? Or is using RecyclerView enough?
  • How about the state of my views? If I use a recycling pattern, can I save the state of each of my fields (even off-screen) and thus save the form without losing data?
  • If I use a recycling template to render one form, how do I handle multiple forms? Can we have a nested RecyclerView? The forms should render one after the other like inside a vertical RV, but if the forms themselves are RVs, how should I handle that?

This is more a question of "good practice" and the right way or one of the right ways to achieve my goal, than the need for a specific answer with example code, etc.

Thanks in advance for your time.

+3


source to share


3 answers


When archiving for a mobile app, I would like to ask the following questions:

Is it good to use Litho? Or is using RecyclerView enough?

  • Are the views being revised correctly: What does this mean to us, think about creating 40-50 views per screen and when the user exits the view, the system should not mark all views for GC, but should be inside some kind of archive list and since we demand it again, we must be able to extract from it.

    Why we need it: GC is the most expensive operation that will cause the application rendering to jitter, we try to minimize the GC to call at this point without clearing the views

    For this I would like to go with liton, justification here as your requirement seems to have more reference variablesviewtypes

    Conclusion: Litho +1, RecyclerView +0

How about the state of my views? If I use a recycling pattern, can I save the state of each of my fields (even off-screen) and thus save the form without losing data?

  1. Saving EditText Content to RecyclerView This is a component, but the same logic should be applied to a checkbox or radioobutton . or as able for lithography here

    Conclusion: Litho +1, RecyclerView +1 both have specific API to achieve public service

If I use a recycling template to render one form, how do I handle multiple forms? Can we have a nested RecyclerView? The forms should render one after the other like inside a vertical RV, but if the forms themselves are RVs, how should I handle that?

  1. This needs to be solved with the help of the user interface, plus technical features: . According to user behavior IMHO I am discouraging nested vertical scrolls, but others have managed to achieve this, you can easily find like in SO, The optimal solution would be to have horizontal scrolling in Andriod or litho recycler view mode like here


NOTE. If you need to know the implementation details, please raise it as a separate issue , I would be happy to help there


UPDATE # 1:

The problem is that on large forms (e.g.> 20 fields) there are a lot of views to inflate and the UI flow will suffer a lot.

UI creation / layout should be done on the backend, only adding to the view should be done on the UI thread. And lithography is built in . However, the same can be achieved on your own recycler, but you need to move away from the UI thread and publish it to the UI periodically.


+2


source


Okay, you have two separate problems. One of them overloads the UI thread and the other is to maintain the state of your anonymous views. About the first part:

1. Leto can help you with this. But you should move all your logic towards litho components instead of android widgets. Since I don’t know your codebase, I don’t know how difficult it is. Using recyclerview will help with recycling the view, but it only matters if you're good at using the list.

2.-It could be if you have a way to save the view of the state of the widget that you can pass to the adapter and then return to the view (I assume you are creating all windows with code and that is, null reference to them) and so ... It sounds messy and it is messy, so I won't try it.

3. -You can, but randomly. The best approach in this case would be to have horizontal recirculation inside vertical recirculation. Nested recyclerviews inside another recyclerview with the same direction create funny problems like "Why is this cell not scrolling". I wouldn't use recyclerview as parent if the view doesn't need it.



Now, to the solutions:

A) UI overloading: As per your pseudocode, you are not bloating stuff. You are creating java objects that are subclasses of View. This is good because creating objects on a background thread is much easier than bloating (parsing XML and using it as arguments to create identical copies of a given resource by calling constructors) on a background thread. While the LinearLayout context constructor requires the UI thread to execute, other things like textviews don't work. This way you can create the latter in the asynthesis, and after you finish generating your entire hierarchy, execute the methods that need the UI thread and add the generated layout to the window. For presentation classes,which do not support creating as Java objects asynchronously, you can have an XML file with just that component, such as linearLayout, and then create asynchronously with the asyncLayoutInflater package. this solution can be implemented in any codebase and will allow you to fully generate UI generation.

B) Tracking View State: Again, I am assuming your view hierarchy is anonymous. If so, you need to create an interface that you can use as a contract to call both persistence and state loading from a lifecycle dependent component such as an activity. After creating such an interface, subclass the widgets and create a subscription / event system in each widget that saves / loads state from the widget every time. Thus, each of the components on the screen can remember its state while remaining anonymous.

+1


source


Just use a RecyclerView and create the views at runtime (you don't inflate, you instantiate) Dynamically creating and adding views shouldn't slow down the UI thread much on mid-range devices. If so, explore bottlenecks elsewhere.

You can do a simple test by adding / removing / setting text with more views dynamically inside a RecyclerView or even a LinearLayout hosted on a ScrollView and you can see that it is smooth

+1


source







All Articles