Question

I'm trying to build a complex form where almost all of the elements are optional. It starts with just a single field and an "add element" button. When you click add, the form shows a Spinner of the types of elements you can add to the form (location, photo, detailed note, timestamp other than "now", etc). When you select an item, it will launch an Activity, and each item has a different associated Activity.

In addition, each choice will have several bits of data, which it would be nice to store "with" the Activity somehow:

  • An icon and the displayed name in the Spinner
  • A key for storing the data in the db (as well as passing to a webservice)
  • A layout for how to display the result on the original form (i.e. a thumbnail for the photo, the lat/lon for the location, etc)

I was considering a set of classes that all extend an abstract FormElement class, and would have static elements for each of the above extra pieces of data. (An additional bump for this solution is how much of a pain Resources are in a static context.)

How can I make this as clean and maintainable as possible? I'd really not enjoy editing five different files to add a new type of element to this form. (Mostly because I can guarantee I'll miss one and spend hours chasing down unbugs.)

Was it helpful?

Solution

A few tips...

  1. Unit tests will prevent "unbugs" :)

  2. When each Activity has obtained the information it needs from the user, call Activity#setResult() with an Intent that contains your per-type data. Intent supports all the Bundle methods, so you can set different types of data as needed.

  3. To support #2, make sure you're using Activity#startActivityForResult(Intent,int) to launch it, and listen for the result in Activity#onActivityResult(int,Intent)

  4. I would probably maintain the list of available "element" types for use with the SpinnerAdapter (e.g., ArrayList<Class<? extends AbstractFormElement>>, and invoke static methods like .getDisplayName(), .getActivityClass(), etc, in the Adapter's getView() method, in order to determine what to display and what Activity to launch.

    In this way, your list would actually contain things like { MyPhotoElement.class, MyTextElement.class, MyDateElement.class, ...}).

  5. As each element is added to the form, add it to an ArrayList<AbstractFormElement>, which will be used to back another Adapter for a ListView. That adapter will dispatch the inflation of a custom view layout, as well as the creation of a ViewHolder, based on what type of object it is -- that will require that each distinct AbstractFormElement will have its own "view type", according to the Adapter. See BaseAdapter#getItemViewType(int) and related getViewTypeCount().

    It's worth noting that these will need distinct view types only if one cannot be converted to the other... For example, if you have two "Elements" that only need to display a string of text in the list, those can both share a "text-only" view type. Likewise, two elements that only display a photo, or can easily convert one to the other (e.g., an icon with a caption, vs a photo thumbnail with no caption), can share a single "image-plus-caption" view type.

With the above in mind, you actually would end up having to modify different files to add a new type (well, I guess technically you could have them all in one file, as inner classes, but there's really no good argument for doing that), but if you've done your interface API correctly, and follow good OO practices, and implement good unit tests, you'll considerably reduce the amount of effort required to find bugs -- simply because most of the things involved in adding a new type would actually force a compiler error if you do it incorrectly. Add to that the fact that a proper unit test suite will be able to programmatically add all possible types, and ensure that everything displays properly, and you should have a pretty streamlined process for easy extensibility :)

It sounds like a lot of work, and it might seem tedious and verbose at first... But the end result is actually much more maintainable, especially if your list of element types is going to be fairly extensive.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top