I’ve seen quite a few discussions pop up in various forums like Stack Overflow and the Android Developer Google Group about dynamically creating U.I. in Android applications. The official Android documentation seems to be very keen on the xml for layouts approach. This approach allows you to easily separate views from logic, which is a good thing. However, writing xml files for U.I. is not always flexible when working with dynamic data.
I’m working on a project right now that involves dynamically generating form-based user interfaces. The interfaces are assembled based on JSON schema files generated by a web service. I’ve written a small framework for handling this kind of task. In this post I’ll walk through the basic usage of the framework. I won’t go into a much detail about how the internal code is put together, but I will cover the basic API and the schema structure.
Core Features
- auto-creation of form-based U.I. from json schema files
- auto-population of form-based U.I. from existing json data ( must match schema format )
- auto-layout based on priority indicated in schema ( also handles creating scroll bars for forms taller than the screen )
- conditional visibility of form elements based on user input
- functionality for saving user input into compatible json format
Download the source code here.
Basic API Usage
This section will explain the methods for creating, populating and saving the state of a form-based u.i.
Form Activity
The FormActivity class is an abstract class that takes care of most of the heavy lifting for you. It is intended to be sub-classed in your application. In the example project the sub-class is called FormGeneratorExample. It will work just like other Activity classes in the Android framework. Below we will look at its public methods.
generateForm( String data )
This method is responsible for parsing the JSON schema and creating the form. It should be supplied a string of valid JSON data. Note that the method does not require a JSONObject. There is a method in the FormActivity class for converting a file to a String. To generate a form-based U.I. we use the following method which produces the image below:
generateForm( FormActivity.parseFileToString( this, "schemas.json" ) );
populate( String data )
When supplied a String of JSON data that matches the current schema, this method will populate each field of the form. The syntax is nearly identical to generating a form, again parsing a file with JSON data to a String.
populate( FormActivity.parseFileToString( this, "data.json" ) );
save()
This method zips through each field of the form and caches the current attribute/value pairs into a JSONObject. From the image above it produces this JSON data.
{
"genre":"2",
"imported_from":"1",
"release_year":"1999",
"import":"1",
"label":"1",
"artist":"Boards Of Canada ",
"album_title":"Music Has The Right To Children",
"formats":"1"
}
The Form Schema
As mentioned, each form is created from a JSON schema file. Below is a snippet from the schema included in the example project. It represents a form for audio recordings. The complete schema file is located in the assets folder of the example project. Each field in the schema represents a widget in the form-based U.I.
{
"artist": {
"type": "string",
"id": "0",
"default": "",
"priority": "0"
},
"genre": {
"type": "integer",
"id": "5",
"default": "0",
"priority": "1",
"options": {
"0": "None",
"1": "Rock",
"2": "Electronic",
"3": "Country",
"4": "Hip-Hop",
"5": "Jazz",
"6": "Pop",
"7": "World"
}
}
}
The first field in the snippet above is “artist”. The name of each field is used as a label for the input widget representing the field. This is important to note because it means that the names you give each field in the schema are converted to displayable names. You can use multiple word names by separating words with underscores. As an example, a field with the name “album_title” would be converted to Album Title when displayed as a label for the widget.
Required Fields
Each field in the schema has a few required attributes. These attributes are required because the code that parses a schema uses them to build the widgets in the form-based U.I. The required attributes are:
type – the data type of the field; this value ultimately informs the generator which kind of widget to create
default - a default value for the field; this value should match the data type specified by the type attribute; in the case of Spinner widgets the default should be an integer corresponding to an item in the options list ( not the actual string value )
priority – priority is used to visually order the widgets; by default all widgets are stacked vertically; if you do not need the widgets in a form to be in a specific order you can just set the value to zero; however do not omit this field from the schema
The Type Attribute
The type attribute of each field indicates which type of widget to use to represent the field.
string:
indicates to the parser to create an FormEditText widget; fields of type string also support an optional attribute called “hint”; for text input widgets the hint attribute sets the default text for when the widget contains no text; below is an example:
"release_date": {
"type": "string",
"id": "2",
"default": "",
"priority": "2",
"hint":"Example: 10/30/1999"
},
integer:
indicates to the parser either a FormNumericEditText widget or a FormSpinner widget if there is an options object; below is an example of an integer type with an options object
"genre": {
"type": "integer",
"id": "5",
"default": "0",
"priority": "1",
"options": {
"0": "None",
"1": "Rock",
"2": "Electronic",
"3": "Country",
"4": "Hip-Hop",
"5": "Jazz",
"6": "Pop",
"7": "World"
}
}
boolean:
indicates to the parser to create a FormCheckBox widget; notice that the default value of the boolean field is “0″ and not false; booleans are represented as one or zero in the schema
"import": {
"type": "boolean",
"id": "6",
"default": "0",
"priority": "7",
},
Optional Attributes
Toggles
The framework allows you to specify the conditional visibility of form widgets based on user selections. In the example project there is a field called “import” which is of type boolean and represented in the U.I. as a FormCheckBox. When it is selected an “Imported From” FormSpinner widget is displayed. To achieve this we add an attribute to the “import” field called “toggles”. Below is an example of the “toggles” attribute:
"import": {
"type": "boolean",
"id": "6",
"default": "0",
"priority": "7",
"toggles": {
"1": [ "imported_from" ]
}
},
"imported_from": {
"type": "integer",
"id": "7",
"default": "0",
"priority": "8",
"options": {
"0": "N/A",
"1": "Spain",
"2": "Italy",
"3": "Germany",
"4": "France",
"5": "Japan",
"6": "Australia",
"7": "China",
"8": "United States"
}
}
The syntax of the toggles attribute works like this. The “1″ indicates that when the value of the FormCheckBox changes to “1″ or true make all of the widgets in the corresponding array visible. The field could also indicate that multiple items toggle their visibility or that when the value is set to false or “0″ that other widgets become invisible, as in the example below:
"import": {
"type": "boolean",
"id": "6",
"default": "0",
"priority": "7",
"toggles": {
"1": [ "imported_from", "record_label", "original_release_date", "import_release_date" ],
"0":[ "distributor" ]
}
},
The toggles attribute can also be used with FormSpinner widgets. Below is an example:
"label": {
"type": "integer",
"id": "3",
"default": "-1",
"priority": "3",
"options": {
"0": "none",
"1": "Warp Records",
"2": "Touch & Go",
"3": "Warner Bros.",
"4": "Sony Music",
"5": "S.Y.R.",
"6": "The Leaf Label"
},
"toggles": {
"1":["formats"],
"2":["formats"]
}
},
"formats": {
"type": "integer",
"id": "4",
"default": "0",
"priority": "4",
"options": {
"0": "None",
"1": "Compact Disk",
"2": "Record/Vinyl",
"3": "MP3/Download",
"4": "Cassette",
"5": "8-Track",
"6": "Wax Cylinder",
"7": "Laser Disc",
"8": "Mini-Disk"
}
},
In the example above the formats field will only be displayed when option 1 or 2 is selected.
Note: if you populate a form-based U.I. with existing data and the data makes use of fields that toggle the visibility of other fields this functionality should still work. If it doesn’t work then there is a bug, please leave a comment…
Stability
This is an early version of this little framework. The code has been implemented in my production code, however it still needs to be thoroughly tested. It would be great to hear back from the community on this. If you have suggestions or think certain parts could be improved, don’t hesitate to leave a comment or question.
Future
I am hoping to add a couple of new features to this code as needed. It would be nice if there were a few additional parameters on a per widget basis and I’d like to implement more of the component set. That said, I don’t see a need for this project to go into a massive coding effort. I would like any additional features to be completely optional so that it can still be used as simply as it currently is.
Collaborators
If you have something you would like to contribute to this project don’t hesitate to let me know. It would be great to work with some other coders to optimize and extend what is already written.





Hi,
This is really nice and helped me a lot.
I wanted to know where is the data which is taken from the user actually stored, i know it uses Json Object but what is the location and how to retrieve it for further use.
Thanks
Rashi
Hi Rashi,
Good question!
In one project I worked on I just stored the entire json object as a string in one column of a sqlite table. You could create a sqlite database on the device based on the schema files with columns for each property too. Perhaps that would make a nice utility for the Forms framework ( a sqlite table generator ).
Hope this is helpful.
~Jeremy
wow, it’s cool
really nice!
Wow Jeremy, awesome! I was really looking after a way to render fields in a more dynamic way. Thanks, I will definitelly take a look at your work. I’ve already built a Java web project doing just this and I was wondering the much effort it will take port it to the android plataform.
regards, otávio
Otávio,
Great, look forward to hearing your thoughts!
Thanks,
~Jeremy
Sorry but I am confused about how to download the code from the Google repository – am I supposed to open each file and copy&paste the code from the repository to my Android project?
Hi Chris,
Google Code hosts the files in a Subervsion (SVN) repository. You need to download and install Subversion in order to “check out” all of the files at once. Doing so will allow your version of the code to stay current in the event that updates are made.
If however, you don’t want to bother with SVN, though I recommend you at least check it out, I’ve added a zipped version of the forms example and lib. You can download it here: http://code.google.com/p/makemachine/downloads/list
Hope that helps you out,
~Jeremy
Thanks, I was able to get the files.
Are you purposely outputting the items listed in a the spinners in a different order than what they appear in the JSON?
Hi Chris,
Good question. As far as I understand it, when a JSON object is parsed, the sequence of it’s objects is not maintained. However, the sequence of a JSON array will be. Your best bet is to implement a sorting function on anything that needs to maintain a sequence. Perhaps wrapping all objects in a JSON array would be an improvement.
~Jeremy
Just wanted to let you know I’ve got this runnig on a test app, reading the JSON from a php file, which is pulling the JSON data from a MySQL database.
I modified the code so that it “reorders” the Spinner options based on the order they appear in the JSON.
@Chris
Cool, glad to know that it is working out for you! I wouldn’t mind taking a look at your changes if you want to share. If so, feel free to send the modified source to: jeremynealbrown at gmail.
Jeremy,
It appears we may be working on similar solutions. Perhaps we could collaborate? Could I ask you to take a look at Metawidget (http://metawidget.org)?
We may find some nice points of integration. For example, Metawidget has a ‘pluggable inspection layer’, so perhaps you could plug your JSON parser in there?
Regards,
Richard.
Hi Jeremy thank you for writing such a nice article and this API is very useful. If I use this API in my application then does it will affect the performance(loading and rendering time of form layout and elements) of the application?.
@Vikas Patidar
The project I built this for used forms with up to 70 elements. In general, the view creation is very fast and the scrolling was smooth. I haven’t experienced any performance issues. That said, if you are debugging on an actual device that is logging to the console, you will most likely see a significant delay in the view creation.
Thanks,
~Jeremy
Hi Jeremy, nice example, i new on android and i want to know how i can to put a button in the form with jason, i already run your example but i nned to do the submit but a can´t see the button any where.
Thanks
N03
@N03
The best way to put a submit button is to use the contextual menu buttons. Or, you could change the height of the scroll view that the form resides in and insert a container that with a submit button in it.
Very nice Jeremy, I need to try !!!
Thanks again for such important post.
Very nice Jeremy…exactely what im looking for…please tell me, i would like to implement a schema editor that allow me to generate the json data from my android project instead of gettint it from a web service
do you have any idea ?
thx
Guy
Hi Guy,
Glad that the form generator is working out for you. As for generating schemas from within the app, you could build a database directly on the phone using sqlite and then use that as a model for your schema/forms.
We could use this occasionally.
Do you have a SVN repo setup for it so we don’t have to keep checking for updates?
Hi Brill,
Here is a link to the repo: http://bit.ly/lBoIbO. I have not been working with the Android platform lately. This code base will likely remain the way it is.
Thanks for your interest.
Is this form generator can be used for commercial projects? I see your google code license marked as GPLv3, it looks like close source apps can not adopt that.
This is a great question. Thanks for asking. I have changed to the license to a more liberal MIT license so that the code can be used in commercial closed source projects.
Hi Jeremy,
this is very great, and helped me out so much.
but I’m confused to change the default size of the textview, how to do that ?
Regards,
Bamby
i am new to android environment
i have set the environment and learning android by books
i have downloaded code for dynamic form generatior but how to execute it
is 2010_08_26_android_forms_src_and_example.zip example for windows os or not
please help me
bhushan
gvvit
as i knew to this technology , in less time
finally i got executed the code
it is nice
thank you
but i want information about webservice to create json object and to validate the created form
bhushan
gvvit
bhimvaram
ap