AndroidPub
Published in

AndroidPub

Android DTT #15 — Passing and Validating Data Between Activities Made Easy

In a classic Master-Detail pattern, when one of the items is selected then the MainActivity will send an Intent to launch DetailActivity with some information that is required in DetailActivity. It may be as little as an id of the selected items, but may become much complicated with the DetailActivity requires additional parameters (e.g source for tracking, data that user type into forms, etc).

A common way to do this is to put the required parameters into Bundle that will be included in the Intent

// MainActivity.java
private void onItemSelected(Item item) {
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra(DetailActivity.KEY_ITEM_ID, "id");
startActivity(intent);
}
// DetailActivity.java
public static
String KEY_ITEM_ID = "item_id";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
....
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
String id = bundle.getString(KEY_ITEM_ID);
if (id == null) {
throw new IllegalStateException();
} else {
loadData(id);
}
} else {
throw new IllegalStateException();
}
....
}

This works. But there are things that I personally don’t like. The first one is we need to maintain a String constant as the key for each field. But we won’t do anything else to that String, so it becomes the boring part of the code. The MainActivity also need to check to the DetailActivity on what key to use for storing the ID.

The second is validation. We need to check whether the Bundle that comes with the Intent is not null. Then we need to check if the Bundle contains an item with a certain key. The example above is just validating a single parameter of type String. Just imagine the line of code needed to check 3 or more parameters. And also you might found a bug in runtime when you forgot to add the parameters into the bundle.

Dart & Henson to the rescue

Dart & Henson are two libraries that solve the problem well. Dart will be taking care of injecting fields in DetailActivity from the Bundle as the source. While Henson will take care of the Intent creation. All of that is created using Annotation Processor. It means we don’t need to create the key string. We don’t need to find out in runtime if we are missing a parameter, it’ll be handled compile time.

The first thing we need to do is to add the library into our dependency list.

compile 'com.f2prateek.dart:dart:2.0.2'
compile 'com.f2prateek.dart:henson:2.0.2'
annotationProcessor 'com.f2prateek.dart:dart-processor:2.0.2'
annotationProcessor 'com.f2prateek.dart:henson-processor:2.0.2'

Don’t forget to add the ProGuard configuration if you turn it on (if not, you really should!)

Now we need to add @HensonNavigable to our DetailActivity. After you build the code, place the following code in our onItemSelected(Item) function:

Intent intent = Henson.with(this) // Context
.gotoDetailActivity()
.build();
startActivity(intent);

Now in the DetailActivity add a field of type String called itemId and add @InjectExtra to it.

@InjectExtra String itemId;

Then, in onCreate(Bundle) add the following code to inject the data from Bundle into itemId:

public void onCreate(Bundle onSavedInstanceState) {
...
Dart.inject(this);
...
}

If you try to build the code, it will fail.

Error:(19, 8) error: @HensonNavigable class DetailActivity must not contain any @InjectExtra annotation

Activity annotated with @HensonNavigable can not contains any @InjectExtra parameters. So keep in mind that use @HensonNavigable when the Activity doesn’t need any parameters from the caller.

If we remove the @HensonNavigable and try to build it again, it will still fail.

Error:(31, 25) error: cannot find symbol method build()

Now you see in MainActivity after calling to .goToDetailActivity() you have to call .itemId(String) to be able to call .build(). This is very helpful to identify bug early since we forgot to set the itemId from the MainActivity.

After adding that call to .itemId(String) it will finally build successfully.

Additional tips:

  • You can add @Nullable to a field if it is not mandatory.
  • If you pass null at one of the mandatory parameters, it’ll throw IllegalStateException
  • Parceler works great with Dart&Henson
  • Read the library’s readme in Github. There are many bonuses from the developer

If you like this, hit that heart button and recommend it to your friends.

ADTT (Android Development Tips and Tricks) is a 31 series of blog posts that I’m trying to finish in throughout May. Click here for index.

--

--

The (retired) Pub(lication) for Android & Tech, focused on Development

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store