I have a service which calls a C function through JNI. This function then spawns a pthread
and attaches it to the JVM. I call a Java method from this pthread
which should post a Toast
notification. Unfortunately, as soon as the Toast
notification is called, I get a null pointer exception.
Here is the method that handles the Toast
call in my service class:
public void showToast(final String msg) {
final Context MyContext = this;
Handler h = new Handler(MyContext.getMainLooper());
h.post(new Runnable() {
@Override
public void run() {
Toast myToast = Toast.makeText(MyContext, msg, Toast.LENGTH_SHORT);
myToast.show();
}
});
}
What could be causing the null pointer exception, and how can I fix it?
Is it trying unsuccessfully to take the context from the C function?
Here is the error message
W/dalvikvm( 4010): JNI WARNING: JNI method called with exception pending
W/dalvikvm( 4010): in Ldalvik/system/NativeStart;.run:()V (CallVoidMethod)
W/dalvikvm( 4010): Pending exception is:
I/dalvikvm( 4010): java.lang.NullPointerException:
I/dalvikvm( 4010): at android.content.ContextWrapper.getMainLooper(ContextWrapper.java:104)
Using getApplicationContext
:
I/dalvikvm( 6242): java.lang.NullPointerException:
I/dalvikvm( 6242): at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:109)
The problem is that, when called from a C thread through JNI, we cannot get the context. We must get the context from the Service thread itself. In order to do so:
public class MyService extends Service{
private static Context MyContext; /* get context to use when displaying toast from JNI*/
@Override
public IBinder onBind(Intent intent) {
return null;
}
public void onDestroy() {
}
@Override
public int onStartCommand(Intent intent,int flags, int startid){
MyContext = getApplicationContext();
// do what you need to
return START_STICKY;
}
public void showToast(final String msg) {
Handler h = new Handler(MyContext.getMainLooper());
h.post(new Runnable() {
@Override
public void run() {
Toast myToast = Toast.makeText(MyContext, msg, Toast.LENGTH_SHORT);
myToast.show();
}
});
}
}
This way, we have a static reference to the proper context that we can access with our call from JNI