Launch Intent Pattern
Often when developing Android apps, we come across the situation when we want to pass some data from ActivityA to ActivityB. To do so, we declare a key to be used to pass and retrieve the data in the Bundle. E.g. In ActivityB you might have something like:
public static final KEY_USERNAME = "activityb.username";In ActivityA, you bundle the data like:
Intent intent = new Intent(this, ActivityB.class);In ActivityB, you'd read the data like:
intent.putExtra(ActivityB.KEY_USERNAME, userName);
startActivity(intent);
String userName = getIntent().getExtras().getString(KEY_USERNAME);Now, as you can see, the KEY_USERNAME we declared in ActivityB is all over the place. First of all, the access needs to be public since we need it in ActivityA, outside of the scope of ActivityB. The key, in theory, is only required in ActivityB, since that Activity cares for the data. And as you can visualize, as the app starts getting complex, you see all these variables being referenced in some Activity / Fragment class which is living somewhere else. Since the access is public, when a developer needs to pass something similar, guess what key they will end up using? You're right, the one already defined in ActivityB. This makes the code harder to read and you have to keep a mental map of what constant is declared where in case if you want to use it, let's say in ActivityC.
One way of making the code look clean which I've noticed being used often is the static imports. So, my ActivityA code might look like:
import static mypackage.ActivityB.KEY_USERNAME;
This does make the code a little pretty, but it has some problems associated with it. First off, the documentation says:
Intent intent = new Intent(this, ActivityB.class);
intent.putExtra(KEY_USERNAME, userName);
startActivity(intent);
So when should you use static import? Very sparingly! Only use it when you'd otherwise be tempted to declare local copies of constants, or to abuse inheritance (the Constant Interface Antipattern). In other words, use it when you require frequent access to static members from one or two classes. If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Readers of your code (including you, a few months after you wrote it) will not know which class a static member comes from. Importing all of the static members from a class can be particularly harmful to readability; if you need only one or two members, import them individually. Used appropriately, static import can make your program more readable, by removing the boilerplate of repetition of class names.
In a broader sense, it makes your code unreadable. Imagine a new developer who just joined and is reading the code. It gives an impression that the constant is declared in ActivityA, unless you read the imports, which rarely happens. Only if you're using commonly used variables declared in Util classes should you use static imports.
For clean code let's take inspiration from the Fragment.newInstance() pattern. Like it, we can have a static method declared in ActivityB that builds the Intent needed to invoke itself. For example,
public class ActivityB extends AppcompatActivity {And then from ActivityA (or really any other place from where you want to start ActivityB with a user name), you can call:
private static final String KEY_USERNAME = "activityb.username";
public static Intent launchIntent(String userName) {
Intent intent = new Intent();
intent.setExtra(KEY_USERNAME, username);
return intent;
}
}
Intent activityB = ActivityB.launchIntent(userName);As you can now see, the code to start ActivityB is much cleaner. Also, the static key can safely reside as a private member of ActivityB. If there are multiple ways you can start ActivityB from your code, you can have multiple launchIntent() methods which can also take in different parameters. You can also pass in the caller Activity's context into the launch method and start the Activity from inside the launchIntent() method itself. I know it's not super safe to pass in Activity context into a static method, but if you're careful to not use the context beyond the scope of the static method, you should be good.
startActivity(activityB);
It makes the code easier to read and understand. Also, for huge projects and really important Activities of your app, you can find (almost) all the ways you can start that Activity in one place rather than looking for it all over the codebase.
Comments
Post a Comment