When I switched from working on Yelp’s iPhone app to our Android app, one of the first things I encountered was the radical difference between the equivalent classes to handle what I normally consider a “screen” or “page” of an app. On Android, an Activity handles what on iOS you use a UIViewController for, but they work in fundamentally different ways. One of the biggest differences is that on Android you can’t just instantiate a new Activity and display it like you can with a UIViewController. Instead you create an Intent and tell the system to start an Activity based on that Intent.

This works fine for simple Activities, but things get complicated when you have a complex data object which you want to display in a new Activity. Android doesn’t let you pass arbitrary objects between Activities. As this Android google group discussion points out, data passed to Activities must be placed in globally-accessible state, stored on the device’s flash memory, or passed inside an Intent. A static singleton works for a few objects, but it requires having a place to store all the objects being passed and is generally considered poor design. If you use a static collection to pass multiple objects, the receiver must make sure to remove the objects lest they leak memory. Writing an object to flash is expensive, slow, and requires having a reliable way to write and read an object (such as sqlite or Serializable). Intent seems like it should be great, except all objects written to an Intent must be of a limited set of Java types and classes, or know how to read and write themselves to a Parcel by implementing the Parcelable protocol.

After trying a number of different techniques to pass objects between Activities, we began making the basic objects in our application conform to the Parcelable protocol. This greatly simplified the process of launching new Activities, and allowed our application to save all its objects when suspended via onSaveInstanceState() so recovering from being stopped by the Android system was much easier to handle. As our application grew and we added more and more data objects, I tired of writing similar Parcel- and JSON-related code for each class.

Enter Parcelgen

Inspired by Android’s existing code generation in aapt, instead of manually writing classes that implement Parcelable, I wrote a Parcelable code generator in Python. All it needs to know is the class name, instance variables and types, and a little metadata about each object to create.

I realized that I needed the exact same information to read an object from a Parcel that I needed to read an object from a JSONObject, so I enhanced my script to generate code to do that too.

How it Works

For each object to generate, write a small json description of the object’s members and their types:

{

“do_json”: true,

“package”: “com.yelp.parcelgen”,

“props”: {

“String”: [

“id”, “name”, “imageUrl”, “url”, “mobileUrl”,

“phone”, “displayPhone”, “ratingImageUrl”,

“ratingImageUrlSmall”, “snippetText”, “snippetImageUrl”

],

“int”: [“reviewCount”],

“double”: [“distance”],

“Location”: [“location”]

},

“json_map”: {

“ratingImageUrl”: “rating_img_url”,

“ratingImageUrlSmall”: “rating_img_url_small”

}

}

This is the parcelable description for (a subset of) a Business returned by the Yelp API as used in a sample app I wrote for parcelgen.

Then execute the parcelgen python script to generate the java code for the object:

$ python ~/parcelgen/parcelgen.py parcelables/Business.json src/

This creates two files: _Business.java and Business.java. _Business contains the parcel and json reading/writing logic, and Business contains a CREATOR static variable as required by Parcel. Business doesn’t have any dependencies on the object’s properties. If the json description changes and you re-run parcelgen _Business.java will be overwritten, but not Business.java. This lets you add data and application logic to Business without losing the flexibility to modify the parcel description later (any members added to Business won’t automatically get saved to a Parcel).

Creating and Passing Parcelgen(erated) Objects

Want to pass an object to a new Activity in an Intent? Just use Intent.putExtra() ( BusinessesActivity.java):

intent.putExtra(“business”, mBusiness);

Then, in your Activity’s onCreate():

Business business = getIntent().getParcelableExtra(“business”);

Want to create a list of objects from a JSON array of dictionaries? Check out how the sample app does it:

JSONObject response = new JSONObject(result);

List businesses = JsonUtil.parseJsonList(

response.getJSONArray(“businesses”), Business.CREATOR);

Using parcelgen saves a lot of repetitive code and developer time in applications that are based around a web API. In Yelp for Android we use parcelgen to handle businesses, users, reviews, and other basic data objects. Whenever you tap a business from the search results list, it’s passed to the Activity to display the business through a Parcel with the help of parcelgen.

Read Up

Detailed instructions on how to use parcelgen in your project and some more advanced features are outlined in parcelgen’s readme on github.

There is a working sample Android application on github here you can use as a reference for how to use parcelgen.

Fork me on github

Parcelgen is open source under the Apache 2.0 license and available for anyone’s use and modification on github. Please feel free to submit patches, feature requests, and such on github.

If you use parcelgen in a project, please drop us a line. We’d love to know about other people using it! You can contact me directly through Yelp or through github.

Back to blog