Wednesday, November 21, 2012

Hey rook, abstract activities cannot be launched


I'm not a programming master by any means, but this one felt like a rookie mistake. I was hunting down an InstantiationException. Below is a helper class used to launch a new activity simply by taking in an activity's name in the constructor, then launching that activity in an onClick() event.

public class ActivityLauncher implements OnClickListener {

Class<? extends Activity> mClass;
Bundle mBundle;

public ActivityLauncher(Class<? extends Activity> clazz) {
this(clazz, new Bundle());
}

public ActivityLauncher(Class<? extends Activity> clazz, Bundle bundle) {
mClass = clazz;
mBundle = bundle;
}

@Override
public void onClick(View v) {
launchActivity(v.getContext(), mClass, mBundle);
}

}

The launch activity method comes from another helper class. See that one below:

public static void launchActivity(Context context,
Class<? extends Activity> clazz, Bundle extras) {

Intent intent = new Intent(context, clazz);
intent.putExtras(extras);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}

This structure works great to maintain clean code. Whenver you need to set an onClick() listener that simply launches another class, just new up an instance of ActivityLauncher, passing it the name of the class you want to start. If you need to pass some values to the activity being started, pass in a bundle along with the activity class name. Where did I make a rookie mistake? I passed in an activity that was actually an abstract class. That code compiles, but it leads to InstantiationException, a runtime exception.  It's not quite clear because the constructor is invoked in the tangle of Android source code and not in any code that I've written. I, however, should know that one can't instantiate an abstract class, which also means one can't launch an activity that's defined as an abstract class.

Sunday, November 11, 2012

From now on, I'm putting off choosing a cloud service


It can be tedious to make network calls during the development of a cloud-based application. It's possible to make thousands of calls across the wire. There is a way to reduce the impact of the network during development -- wait until later to decide on a cloud-based solution.

One of the things that stuck with me from an Agile conference last spring was Bob Martin's talk about putting off database implementation as long as possible. He described an application on which he and a partner worked where he knew the application would eventually need to store information in a database. For the most part databases are going to be used in the same way – handling reads and writes of data.

I knew that if I wanted to create an application with a cloud-based backend, that choosing which service to use could be a big deal. But I wanted to minimize the impact of the backend on my application as much as possible and I didn't like the idea of calling though to a cloud-based network during application development.

Having experience with both Google'sApp Engine and Amazon's Simple DB, I found both to have good and bad. Before hearing Uncle Bob speak, the first thing I did was consider which cloud-based storage solution to pick. I spent most of my time weighing the pros and cons of each service. Having worked with Amazon Simple DB in the past, including on some proof of concept projects at Northwoods, I knew Amazon was a reliable, and well documented service. But at the beginning of this project, I ended up choosing Google's AppEngine. AppEngine seemed to have the easiest cloud solution to implement. With AppEngine, Google offered an Eclipse plugin that made it simple to simulate a cloud environment. AppEngine also provides a starter project that wires up the network access ahead of time. The project even implements a push notification architecture.

However in experimenting with AppEngine, I found my implementation started to become closely tied with the implementation of the cloud-based backend. I had cloud-based database calls in nearly every activity. These activities also were tied to Googles object-relational model. I started to think that it wasn't in my application's best interest to have proxy objects that can only talk to one kind of service.

The tighter coupling with Google also became more apparent when it decided to bring its Cloud to Device Messaging service out of the beta phase and into full production. There was enough of a difference migrating to the new version of the service that it didn't make sense to further bind the application to Google. There was far too much left to be done on the actual program, and what if by the time it was done, Google's Cloud service changed again?

Turns out what I ended up doing (and should have done in the first place) was put off the real database stuff. The best way I've found to write a cloud application is to create an interface that will serve as my application's face to the cloud. I can simulate interaction with the cloud by making calls through this interface to a class that implements this interface and returns the expected data. Essentially I can implement an in memory database using HashMaps that function as if I were making calls to a reliable and fast network. When the time comes to actually choose a cloud solution, I'll use the adapter pattern and create a class that implements my application's data access interface as well as the interface provided by the cloud solution provider of my choosing. In this adapter class is where I can put the logic to handle network conditions. One of the major changes I'll have to keep track of is creating the UI screens that must be present to handle loading data from the network. In this architecture, those pages can get lost since the “network” calls return asynchronously during development.

This approach has had many merits, especially when it comes to mocking and test-driven development. Although the Google AppEngine solution allowed me to debug with breakpoints on a local server, this approach of defining my own interface has allowed me to create mocks without a concern for what is happening on the other side of the wire. Since the database interface is injected into a base activity, it is available to all other activities that inherit from it. This is useful for mocking and test driving with Robolectric. This architecture also has forced me to keep logic in the application layer while keeping the cloud database with the sole responsibility of storing and retrieving data.  

General Architecture


Saturday, November 3, 2012

A method organization strategy for Android activities


Using the principles of low-coupling and high cohesion, our class files shouldn't balloon out of control to the point where single line method signatures get lost amongst the trees, but it doesn't hurt to have an extra layer of organization on which developers can agree. It's an inevitable fact that we have to read each other's code. The list below reflects how I organize methods in an Android Activity class at the moment. I wouldn't mind making this an exhaustive list so if you got any ideas....speak up.. :).
  1. Constructors – default followed by paramterized (public, then package, then private).
  2. Any method that overides Activity lifecycle events, starting with onCreate(). The rest should follow in the order that they are called on the activity lifecycle stack.
  3. Next come any classes that override an interface. These should all be appended with the @Override annotation.
  4. Include the @Override annotation also on any methods that override an abstract class implementation. First list the methods you are forced to override from the abstract class, followed by the methods that you chose to override.
  5. Next come any methods that are being optionally overriden from any concrete superclass.
  6. Then we list our public methods that are specific to this class. I like to start with the public methods that have more meat to them, followed by the getters and setters.
  7. Package-level implementations are next.
  8. Private methods follow the package-level ones.
  9. After the private methods come the abstract methods. I like the abstract methods down here so that when another programmer is looking at this abstract class and wants to find out which methods this class does not implement, he or she can scroll to the bottom. Those one-line method signatures don't get lost among the methods that have a heavier implementation.