Rien de spécial
Le blog de Régis

NullPointerException in PendingIntent.java:195

Mobile development is difficult for a number of reasons. But Android framework does not help…; This is my complaint of today (read more in the series Android bugs)

If you want to display a notification in the Android status bar, the the javadoc for NotificationManager makes you believe that something like this will work

int icon = android.R.drawable.stat\_notify\_chat;
CharSequence tickerText = « Bonjour! Tu veux qu’on déjeune ensemble ce midi? »;
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);

int id = (int) (Math.random() * 100);
notificationManager.notify(id, notification);

Well, it doesn’t. My text is only the ticker, but the notification bar can also be expanded. Hence a title and a message must be defined. Actually, you must add a LastestEventInfo

NotifActivity context = this;
String contentTitle = « You have a new messsage »;
String contentText = « regis@example.com (42) »;
PendingIntent contentIntent = null
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

So far, so good

Because, I have used a random id, the notification will not be updated, and each time this code is executed, it will add a new notification.

You might wonder what contentIntent is. It is a container for starting an activity if the notification is « clicked » (in that case one would expect to display the content of the message). So I quickly create a MessageActivity, and the notification can now be built with:

int requestCode=0; // javadoc says « private code curently not used »
Intent intent = new Intent(context, MessageActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, Intent.FLAG\_ACTIVITY\_NEW_TASK);

Since I’m always complaining, can anyone in the Android team explain why the put fields which are « not used » (sic)?

This eventually works and when we click on the notification, Android opens the MessageActivity

All this is not very complicated, but it is 14 lines of code just to add one notification. So I externalized all this in a builder, which makes things much quicker to use:

But it also introduces a bug. Imagine one of my notification doesn’t need to start an activity, it would make sense to do

displayNotification(« That will kill you », MessageActivity.class);

But Pending intent doesn’t say it doesn’t accept null in the doc, nor does it raise a proper IllegalArgumentException.

Instead, your application will crash with

<br /> FATAL EXCEPTION: main<br /> java.lang.RuntimeException: Unable to start activity ComponentInfo{info.decamps.droid.demo/info.decamps.droid.demo.NotifActivity}: java.lang.NullPointerException<br /> at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)<br /> at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)<br /> at android.app.ActivityThread.access$600(ActivityThread.java:123)<br /> at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)<br /> at android.os.Handler.dispatchMessage(Handler.java:99)<br /> at android.os.Looper.loop(Looper.java:137)<br /> at android.app.ActivityThread.main(ActivityThread.java:4424)<br /> at java.lang.reflect.Method.invokeNative(Native Method)<br /> at java.lang.reflect.Method.invoke(Method.java:511)<br /> at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)<br /> at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)<br /> at dalvik.system.NativeStart.main(Native Method)<br /> Caused by: java.lang.NullPointerException<br /> at android.content.ComponentName.<init>(ComponentName.java:76)<br /> at android.content.Intent.</init><init>(Intent.java:3122)<br /> at info.decamps.droid.demo.BaseActivity.displayNotification(BaseActivity.java:37)<br /> at info.decamps.droid.demo.NotifActivity.onCreate(NotifActivity.java:12)<br /> at android.app.Activity.performCreate(Activity.java:4465)<br /> at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)<br /> at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)<br /> </init>

I think it reveals how poor the javadoc for Android is, and how fragile the framework is. It certainly does not explain why Google engineers offer the same kind of buggy code. And it reminds us all that Android fragmentation is a real problem, since passing null apparently worked in the past.