简体   繁体   中英

Android - Null pointer on Toast call

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)

Try this:

Toast.makeText(MyContext, msg, Toast.LENGTH_SHORT).show();

That's how i've always done it and it will only crash if msg isn't null.

Try that and if that doesn't work check for msg being null before. You could do something like this.

if (msg.equals(null){
msg = "Variable was null";
}
Toast.makeText(MyContext, msg, Toast.LENGTH_SHORT).show();

By the way i forgot to consider that you might not get what this means.

If you get the toast message Variable was null when you run your app. that means wherever the method call comes from is sending a null string. You need to find the method call and figure out why the variable it's passing is null.

For instance search your project for this showToast(

Search for that call, as many times as it's made. If there is more than one call you can check the string at each call before you make it, and if it's null you can add a string that will help you identify where the call came from. you can use the code i put above before each call, but checking the variable sent instead. then making it equal "call from xxxxx is null""" xxxx being the location that the call is made from. then you can figure out why the variable sent is null.

also try what i said with getApplicationContext() instead of MyContext

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM