Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random NullPointerException on Google Maps API v2

I've been working with Google Maps API v2 (version 3.2.25 (761454-30)) on my Android app, and sometimes it works perfectly though sometimes (which is getting each time more often) I'm getting a NullPointerException. I'm not doing anything too different with the map, and it has happened on some Nexus 4 as well on a Nexus S. I've found an issue on the gmaps-api-issues project though I don't get any help from there. I'mputting the question here then with some details to see if someone has gone through this already.

As I said, I'm not doing anything any different as what they suggest on the API, and the only things I think I may be doing which not everyone necessarily does (and that may be causing some problem, idk) is:

  • I'm using a SupportMapFragment inside another Fragment, a.k.a. as a nested fragment. I'm also using ActionBar Sherlock, so that other fragment is a SherlockFragment just to say.
  • I'm instantiating the SupportMapFragment on my Fragment's onCreateView (instead of putting it on XML) and then addind it to a FrameLayout on my layout.
  • I'm applying some Y translation to the map (with nineoldanroids), so that I can acquire an effect close to the one as on the Foursquare app (though I've never got an NPE on Foursquare).
  • I'm creating and clearing some markers as the user progresses on the app (that shouldn't be it, since the bug happens on startup, while loading the framgent)

That is much it, I won't put the code here since it is not like it's just a snippet which is not working but I've listed much of what I'm doing. Here is the stack trace (it is always practically the same):

java.lang.NullPointerException
at java.nio.ReadWriteDirectByteBuffer.put(ReadWriteDirectByteBuffer.java:137)
at java.nio.ShortToByteBufferAdapter.put(ShortToByteBufferAdapter.java:163)
at maps.z.d.d(Unknown Source)
at maps.z.d.a(Unknown Source)
at maps.aq.a.a(Unknown Source)
at maps.aq.ao.b(Unknown Source)
at maps.aq.ao.a(Unknown Source)
at maps.v.g.a(Unknown Source)
at maps.v.g.b(Unknown Source)
at maps.p.p.l(Unknown Source)
at maps.p.p.run(Unknown Source)
like image 736
Victor Elias Avatar asked Oct 27 '13 22:10

Victor Elias


Video Answer


1 Answers

Well, I managed to "fix" this issue. It isn't actually a fix but at least I'm avoiding a crash on my app when that exception is thrown. What I did was to override the default uncaught exception handler and suppress crashing the app when the uncaught exception is this one. The crash was because of a NullPointerException and it always happened on a GLThread (must be from the drawing code from Google Maps). So I check if all the prerequisites apply, and if so, I send a broadcast with a custom action so I can listen for that broadcast on the fragment on which I use a Google Map, replacing my SupportMapFragment when I get one. Since we got an uncaught exception, the GLThread is interrupted and the drawing to the Google Maps Fragment is suspended, so we do need to replace the Google Maps Fragment for the map to work again.

Here is the code I had to add:

On my Application's onCreate:

final UncaughtExceptionHandler defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread thread, Throwable ex) {
        if (ex instanceof NullPointerException && thread.getName().startsWith("GLThread")) {
            for (StackTraceElement stackTraceElement : ex.getStackTrace()) {
                if (stackTraceElement.getClassName().contains("maps")) {
                    sendBroadcast(new Intent(ACTION_MAPS_NPE));
                    return;
                }
            }
        }
        defaultHandler.uncaughtException(thread, ex);
    }
});

And then on my Fragment which uses a Google Maps Fragment, I register this broadcast receiver right before adding the SupportMapFragment to the layout on onCreateView (and unregister it on onDestroyView):

private class GoogleMapsNPEReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Fragment mapFragment = getChildFragmentManager().findFragmentById(R.id.map_fragment_container);
        if (mapFragment != null) {
            getChildFragmentManager().beginTransaction()
                    .replace(R.id.map_fragment_container, SupportMapFragment.newInstance())
                    .commit();
            mMapInitialized = false;
            // We won't have onResume to initialize our map anymore. Try to initialize it after 100ms.
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (getGoogleMap() == null) {
                        handler.postDelayed(this, 100);
                    }
                }
            }, 100);
        }
    }
}

Hope this helps anyone with that same issue. If anyone has an actual fix for it please let me know.

like image 193
Victor Elias Avatar answered Nov 05 '22 18:11

Victor Elias