Saturday, June 25, 2011

JUnit testing with Android

Just a short note for those of us who are familiar with writing unit tests in normal Java environments (i.e. not Android's dalvik):

Do not import any unit test methods or classes.

The libraries will not be available at runtime on the device and you will get NoClassDefFoundErrors for everything from Assert to hamcrest Matchers. It's reflex to type "import static org.hamcrest...." or "import static org.junit...." etc at the top of your test fixture class, but resist the habit when developing for Android.

Just extend ActivityInstrumentationTestCase2 and call the assertion methods that you inherit, like so:
assertTrue(message, condition);
Note that it's not Assert.assertTrue().

Aside from that, following Google's Hello Testing guide will work without gotchas.

Friday, June 17, 2011

Hamcrest imports

I'm putting this down in writing because I keep getting asked. What are those static imports from hamcrest? You know, the ones that we always use?

import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.*;

Sunday, February 6, 2011

2Easy Battery Grapher

Available on the Android Market!














A big problem with these smartphones that alert you to new email and show everyone's Facebook updates is that they chew through battery power like Bugs Bunny through a carrot. Towards the end of the day we are all wondering why exactly our batteries are so low. Was it a constant drain all throughout the day or was it playing games and writing email during the morning commute?





Graphing the battery shows the 'when' of power drain and you can scroll it left and right with your finger.
The menu options give you some extra help and the ability to send feature requests to me directly.




 




Showing what apps were running at any one time helps to show the 'what'. It looks nicely colourful and 3D too.











It is easily my most complex Android app to date and I plan to take it a lot further. Eminently useful for myself, I hope that a lot of other people find it useful too.

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.