Singletons and Services and Shutdowns Oh My

Passing data back and forth between activities on the Android platform is one of the more challenging aspects of understanding Android. Understanding how this data is managed by the OS is the difference between getting flooded with Error Reports and bad reviews and getting glowing praise and eternal gratitude. Well maybe not to that extent, but having a good background in passing data can make your code much easier to manage and cleaner to read (and for that you have my gratitude) So in passing the data there are essentially two types Persistent and strangely enough, Non-Persistent data types. The Persistent types are best handled by preferences, files, databases or content providers and they are pretty detailed in their operation. If you need to keep data over the length of more that one session consider using Persistent data stores. On the other hand, there are often times where transient data needs to be stored for one session and passed between activities. To handle that there are a couple of ways to handle it. This page details some of the methods, and it is repeated here for convenience;
How do I pass data between Activities/Services within a single application?
It depends on the type of data that you want to share:
Primitive Data Types
To share primitive data between Activities/Services in an application, use Intent.putExtras(). For passing primitive data that needs to persist use the Preferences storage mechanism.
Non-Persistent Objects
For sharing complex non-persistent user-defined objects for short duration, the following approaches are recommended:
The android.app.Application class
The android.app.Application is a base class for those who need to maintain global application state. It can be accessed via getApplication() from any Activity or Service. It has a couple of life-cycle methods and will be instantiated by Android automatically if your register it in AndroidManifest.xml.
A public static field/method
An alternate way to make data accessible across Activities/Services is to use public static fields and/or methods. You can access these static fields from any other class in your application. To share an object, the activity which creates your object sets a static field to point to this object and any other activity that wants to use this object just accesses this static field.
A HashMap of WeakReferences to Objects
You can also use a HashMap of WeakReferences to Objects with Long keys. When an activity wants to pass an object to another activity, it simply puts the object in the map and sends the key (which is a unique Long based on a counter or time stamp) to the recipient activity via intent extras. The recipient activity retrieves the object using this key.
A Singleton class
There are advantages to using a static Singleton, such as you can refer to them without casting getApplication() to an application-specific class, or going to the trouble of hanging an interface on all your Application subclasses so that your various modules can refer to that interface instead. But, the life cycle of a static is not well under your control; so to abide by the life-cycle model, the application class should initiate and tear down these static objects in the onCreate() and onTerminate() methods of the Application Class [my emphasis]
Being as I come from a java EE background the first decision was to use the singleton class and allow the instance to be available across the VM. The singleton design pattern is fairly well-known and is a good easy way to manage control across many activities. In some previous projects I have used them to manage HTTP connections, image caching and global application configuration to much success. However, this is the important part to consider when using singletons which is very important; Android OS can and will terminate your singleton and not even tell you about it. I highlighted that in bold because if your design depends on singleton patterns you naturally assume they are going to stay persistent through the VM. These are frustrating errors and difficult to track down and even more frustrating for your users. For instance consider this piece of code: In your main activity;
@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);SuperSingletonManager.create(this);}
And your singleton;
private static SuperSingletonManager instance;private SuperSingletonManager(Context context){// do stuff once}protected static SuperSingletonManager create(Context context) {instance = new SuperSingletonManager(context);}protected static SuperSingletonManager getInstance() {if (instance == null)throw new NastyException("Oh God Why?");return instance;}
Seemingly you should be able to call SuperSingletonManager.getInstance() at any time and get access to the static instance. However, this isn't the case. If the launching activity is removed by the OS (it happens, a lot) while you are on another activity, that static instance will be gone. So when you make that SuperSingletonManager getInstance() call you are only going to get a nasty exception. This also means that if any of your functions in SuperSingletonManager make use of the Context those will throw errors. Ack. But I really, really like singletons. So do I. And far be it from me to tell you how to architect your code. The only stipulation is that the singleton should abide by the lifecycle model. We can do this by launching the singletons from a service and binding that service to the launching activity. To the Android purists, and common-sensists out there you might just say "Why not just use a service instead of a singleton?". Sure, makes sense but this post is about singletons and how to get them working and not common-sense. So here is the class that will do all that;
public class SingletonService extends Service {
private final ISingletonService.Stub mBinder = new ISingletonService.Stub() {
public void startSingletons() throws RemoteException {
initializeSingletons();
}
public void stopSingletons() throws RemoteException {
shutdownSingletons();
}
};
public IBinder onBind(Intent intent) {
return mBinder;
}
protected void initializeSingletons() {
SuperSingletonManager.initialize(getApplicationContext());
}
private void shutdownSingletons() {
SuperSingletonManager.shutdown();
}
}
When you start your main activity bind the service using bindService() , and make a call to the startSingletons() method. This will launch your singletons under the lifecycle of the service. This will ensure they are active for the life of your application session. Also, make sure to unbindService when you are finished. Nobody likes developers that don't clean up after themselves. Good luck and if you actually use this method let me know! John
Android Development and the Case of the Missing Google Maps Reference SDK
The Android Developer site has moved a bunch of links around to remove a lot of the Google branding from the community. Technically speaking Google drove the project and owns a lot of the development but it is an open-source community and probably should avoid proprietary and company specific codebases within its structure.
That at least what I assume they were thinking when they yanked the com.android.maps reference documentation from the site. For instance if you were looking for the MapController reference you would run a Google search for it and the first link is this:
http://code.google.com/android/reference/com/google/android/maps/MapController.html
Which returns a bug fat 404. The proper link is at:
http://code.google.com/android/add-ons/google-apis/reference/index.html
Android/Google get it together! At least put a redirect page up on old links!
Hopefully that saves you some time with the SDK.
Programming with Android Part 4 – Finishing WikiWhere
Continuing from Part 3 we are going to spend the 30 minutes or so to finish the WikiWhere application. So far we have a mapping and location application on the device. The final step is integrating the Wiki sites and displaying them on the map.
1:45 Foosball, Reddit, Digg and Google Reader Break
1:55 Getting the XML feed for the Wiki sites
Now that you've had a long break we can get to the more complicated sections of the code. The Wiki information is collected and provided as a web service by Geonames.org. We will be using the wikipediaBoundingBox XML API to get the information from the service. By making a call to http://ws.geonames.org/wikipediaBoundingBox?north=51.1&south=50.1&east=-113&west=-115 you can get the XML feed of the Wiki Entries in the bounding box in the following format:
-
<geonames>
-
<entry>
-
<lang>en</lang>
-
<title>Max Bell Centre</title>
-
<summary>The Max Bell Centre (often referred to as the Max Bell
-
Arena) is an ice hockey arena in Calgary, Alberta, Canada in the
-
community of Radisson Heights. It seats 2,121 for hockey with a
-
standing room capacity of over 3,000. It is named after George
-
Maxwell Bell, a philanthropist who helped fund the arena's
-
construction (...)</summary>
-
<feature>landmark</feature>
-
<countrycode>CA</countrycode>
-
<population>0</population>
-
<elevation>0</elevation>
-
<lat>51.0422</lat>
-
<lng>-114.0036</lng>
-
<wikipediaurl>http://en.wikipedia.org/wiki/Max_Bell_Centre
-
</wikipediaurl>
-
<thumbnailimg />
-
</entry>
-
...
-
</geonames>
So to get our wiki items displayed on the map we need to:
1. Call the Geonames XML API
2. Parse the XML
3. Display the icons on a MapOverlay
4. Implement the "Search For Wiki Entries" Button
Programming with Android Part 3 – Building WikiWhere
We will continue from where we left off in the last instalment and extend our basic application into a more useful application. If you are keeping track, we're an hour and fifteen minutes into our development and we have our application environment setup and ready to program in Android.
Over the next hour we will create an application that will show the wiki entries near our location, display that information on a map and embed the wiki page into the application. This application highlights three key features of the Android platform;
- Focus on LBS that makes locative media easier to produce.
- Deep web integration from consuming web services to embedding web page.
- Â Simple map integration via Google Maps.
What is WikiWhere
WikiWhere is a buzzword-compliant mobile application that gives you access to local wiki knowledge where ever you are. Using your Android phone, WikiWhere searches wiki for entries near your location and passes that information to you. Discover your neighbourhood or visit others.Â
1:20 Back from Break. You aren't paid to sit there you know.
We are now going to get started with the WikiWhere application. Let's go through the first step and create an application shell using the Eclipse project builder. Just as in the previous part, select File >> New Project >> Android Project to launch a new project. Add the details for WikiWhere. I've attached a screenshot of the details below.
Step 1. Create the MapView
The main user interface will be a MapView so we want to change the interface of our WikiWhere class from Activity to MapActivity and implement the onRouteDisplayed method.
-
package demo.WikiWhere;
-
-
import com.google.android.maps.MapActivity;
-
import android.app.Activity;
-
import android.os.Bundle;
-
-
public class WikiWhere extends MapActivity {
-
public void onCreate(Bundle savedInstanceState) {
-
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.main);
-
-
}
-
-
protected boolean isRouteDisplayed() {
-
return false;
-
}
-
}
Next we have to implement the map in the view. Android separates the device layout / views from the source code to simplify development. A graphic designer can modify the XML layout without impacting the underlying source code. I'm a strong believer in letting programmers do the programming and not the UI or graphic design. Windows 3.1 was designed by programmers. Case closed.
Programming with Android Part 2
In this article we will install the tools for programming in Android and produce our first application.
If you're a more experienced developer or already have installed the tools feel free to skip ahead or take a long lunch and be back at 1:00. As I mentionned in Part 1 this series of articles is focused on getting a new developer up to speed with Android and programming in one afternoon.
So here we go;
12:00 Installing the Basics
The first step is to setup your environment for testing and development. We will need to download a couple of tools to begin with. Find the download for your OS and click through the installers on the page.
1. Sun Java JDK 1.5 or 1.6 (Sun calls it 5 or 6, why because marketing said so).
2. Eclipse 3.4 Ganymede
(Note: I didn't manage to get the SDK installed in Fedora Eclipse version,you might want to try another version if you are using that OS.)
3. And of course, the Android SDK
When installing the tools make sure that you follow the order. There are some dependencies that each will require.
12:30 Configuring Eclipse for Android
Once you have installed all the tools on your system we are ready to install the components that will help you debug and interact with the Android emulator.
Eclipse is configured with its own installer so this task is pretty routine*.
- Click help>>Software Updates
- Click the Available Software tab and select Add Site from the right hand side
- When the dialog box pops up enter the following address
https://dl-ssl.google.com/android/eclipse/
and select OK.
- The google address should appear in the main text column on the left. Select that address. Chose the developer tools and click Install in the top right
- Agree to the terms, download the tools and restart Eclipse.
- Coffee. After all you are working through lunch the least they can do is give you free coffee.
- Once Eclipse restarts, select Window>>Preferences
- Choose Android and select Browse to select your Android install directory from above.
*Eclipse 3.3 has slightly different method to install files. Check here for more details on that process
That's it. Android is now up and running in your Eclipse environment. We can begin to program our first Application. Not bad for a lunch hour.
