views:

552

answers:

4

I have a relatively simple MapActivity that I'm trying to make display a list of "camps" within a given map region. I've created a custom subclass of OverlayItem called CampOverlayItem, a custom ItemizedOverlay called CampsOverlay that returns CampOverlayItems, and of course a MapActivity subclass that populates the map.

I'm pulling the overlay data from a database using an AsyncTask as created in my activity. The AsyncTask is triggered from a ViewTreeObserver.OnGlobalLayoutListener attached to the MapView.

In the onPostExecute method of the AsyncTask, I create a new instance of my CampsOverlay class and pass it a list of the camps returned from the database (which are fetched in doInBackground). I then call:

mapView.getOverlays().add(newOverlay);

where newOverlay is the CampsOverlay I just created. All of this code runs without error, but when the Map tries to draw itself, I get a NullPointerException with the following stack trace:

java.lang.NullPointerException
   at
com.google.android.maps.ItemizedOverlay.getIndexToDraw(ItemizedOverlay.java:
211)
   at
com.google.android.maps.ItemizedOverlay.draw(ItemizedOverlay.java:240)
   at com.google.android.maps.Overlay.draw(Overlay.java:179)
   at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:
42)
   at com.google.android.maps.MapView.onDraw(MapView.java:476)
   at android.view.View.draw(View.java:6274)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1526)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1524)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.View.draw(View.java:6277)
   at android.widget.FrameLayout.draw(FrameLayout.java:352)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1526)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1524)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1524)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1524)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1524)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.View.draw(View.java:6277)
   at android.widget.FrameLayout.draw(FrameLayout.java:352)
   at android.view.ViewGroup.drawChild(ViewGroup.java:1526)
   at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1256)
   at android.view.View.draw(View.java:6277)
   at android.widget.FrameLayout.draw(FrameLayout.java:352)
   at com.android.internal.policy.impl.PhoneWindow
$DecorView.draw(PhoneWindow.java:1883)
   at android.view.ViewRoot.draw(ViewRoot.java:1332)
   at android.view.ViewRoot.performTraversals(ViewRoot.java:1097)
   at android.view.ViewRoot.handleMessage(ViewRoot.java:1613)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   at android.os.Looper.loop(Looper.java:123)
   at android.app.ActivityThread.main(ActivityThread.java:4203)
   at java.lang.reflect.Method.invokeNative(Native Method)
   at java.lang.reflect.Method.invoke(Method.java:521)
   at com.android.internal.os.ZygoteInit
$MethodAndArgsCaller.run(ZygoteInit.java:791)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
   at dalvik.system.NativeStart.main(Native Method)

Because it seems particularly relevant, here is the code for my ItemizedOverlay subclass:

public class CampsOverlay extends ItemizedOverlay<CampOverlayItem> {
    private ArrayList<Camp> camps = null;

    public CampsOverlay(Drawable defaultMarker, ArrayList<Camp> theCamps)
{
        super(defaultMarker);
        this.camps = theCamps;
    }

    @Override
    protected CampOverlayItem createItem(int i) {
        Camp camp = camps.get(i);
        CampOverlayItem item = new CampOverlayItem(camp);
        return item;
    }

    @Override
    protected boolean onTap(int index) {
        // TODO Auto-generated method stub
        return super.onTap(index);
    }

    @Override
    public int size() {
        return camps.size();
    }

}

Does anyone have any idea what could be happening here? I've attempted to verify that everything I have control over is non-null. I can provide more code if necessary.

+6  A: 

I do not see where you are calling populate() on your CampsOverlay.

Here is a sample project showing asynchronous loading of overlay items -- perhaps it will give you some ideas, if populate() is not the issue.

CommonsWare
You're totally right, thanks Mark. You'd think I would have looked harder at your sample code before asking this question. Now I just have to figure out why the overlay items aren't appearing ;)
lyricsboy
+1  A: 

He is correct. You must call populate() to populate the overlay. You may want to create all the overlay items in the constructor, call populate, and in createItem just return the item from a list.

BrennaSoft
Is there an advantage to creating the items in the constructor instead of one at a time inside createItem? From my reading of the documentation, ItemizedOverlay will cache the results of createItem, so there isn't necessarily a need to hang on to those in my subclass as well.
lyricsboy
A: 

I have a related question. I have a thread that creates my ItemizedOverlay. My code is just like the sample project mentioned above. Should the populate call inside the ItemizedOverlay constructor be made on the UI thread?

I just released my app and it has been working great. I did get one crash report with the Exception:

java.lang.NullPointerException: at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:42) at com.google.android.maps.MapView.onDraw(MapView.java:494) at android.view.View.draw(View.java:6535)

I have also heard my app is crashing on the Droid X but I can't seem to reproduce the problem using the emulators. Might have to get a new phone :)

Thanks!

Randy
You'll get a wider audience and a better response if you post this as a question on its own, instead of as an answer to mine.
lyricsboy
Thanks for the tip. The problem I was having with the Droid X crash is explained here: http://groups.google.com/group/android-developers/browse_thread/thread/43615742f462bbf1/f29ee0a153d98f93
Randy
A: 

"Now I just have to figure out why the overlay items aren't appearing"

In case you didn't, it's because you have to use a static function on your Drawable that will explain how is your marker positioned.

You can use this, in your CampsOverlay constructor:

super(boundCenter(defaultMarker));

This will indicate that the origin of your Drawable is the center. You can also use boundCenterBottom() to indicate that the origin is the bottom center of the Drawable.

Bicou