Saturday, January 29, 2011

How to run in the background

So you are making an app that reads stuff in the background and posts to the screen. I did this for my battery graphing app. Another example would be an email program that tells you when you have new mail.

It's all fine except that the 'background' running doesn't happen a lot of the time (though sometimes it does, confusingly). Solution: recognize that Activities are supposed to run in the foreground and for your background tasks you need a Service.

Activities and Services are quite similar, the main differences being that Services don't have GUIs and don't get killed when the user hits the 'back' button or the system decides that it needs extra resources to render youtube videos of cats beating up iPads.

To start your service write this code in your activity, probably inside onCreate():

startService(new Intent(this, MyService.class)); // start doing stuff asynchronously (can be called multiple times)

Now create a class MyService:

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }
   
    @Override
    public void onCreate() {
        super.onCreate();
        // insert your code here
    }
   
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
       
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }
}

Et voilĂ , your service will be started from your activity and will continue to run in the background until you kill it or the device shuts down, despite your activity opening and closing like Pacman's mouth.

Android library project gotchas

Android library projects have some hidden gotchas that commonly snag developers. Here are solutions to save you the hassle.


Android permissions are not inherited across projects.
So your library project is working fine and you make a main project for release and suddenly it stops working. What the crazy?

If your library project has a permission (e.g. android.permission.WRITE_EXTERNAL_STORAGE to save files on the SD card) then your project that uses it will also need this permission, and you have to add it manually.








No two projects can have the same namespace.
If they have the same namespace then in Android's rules they are different versions of the same app. They will write over each other's data and one can't be a library of the other.
I usually name my main project's namespace like 'com.example' and the library project's 'com.example.lib'.


Project refactoring can force you to make new preferences and data.
So you decide that some of your code would be better in a library project for tidiness and reuse. Good for you; this will save you time reinventing the wheel and searching through your code. Unfortunately some of your classes are now in a new namespace, so all those calls to SharedPreferences and file access now refer to that new, virgin namespace that has no data until you run your reorganised app for the first time. If you've built up nice, realistic test data on your emulator or test device then you will no longer see it.
Try to start with your projects arranged in the structure that you think you will have at the end (e.g. a main project and a library project).















Eclipse gets out of synch.
So you open up your library project to fix a bug but when you run your app you don't see any evidence of your code changes. You recompile and try again. And again. And again. Then you insert debugging print statements and popup dialogs to make sure that your code is being run, and as you suspect they don't appear. Then you go crazy at your computer. What is happening?
You are editing inside your library project and Eclipse keeps some sort of cached copy 'inside' the projects that reference it. You can see it in the Package Explorer with '_src' appended to its name. Refresh this and your code (with all of the crazy debugging statements that you just added) will run as you expect.
Next time you can just open up the files from here directly without going to your library project.