Question

This in a bit complex issue so read carefully.

I have tried to realize a map that

-shows my current position,

-when I click on a point in the map, the app should place a custom geoPoint getting latitude and longitude to pass these to an activity to create a new Pub object

-the map on start must show the positions of Pubs saved before

Following this tutorial I have created these class

Class MyMap:

public class MyMap extends MapActivity implements LocationListener {
    private MapView mapView;
     private LocationManager locManager;
     private MapLocationOverlay itemizedOverlay;
     GeoPoint point ;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Inflate our UI from its XML layout description.
        setContentView(R.layout.mymap);

        mapView = (MapView) findViewById(R.id.mapView);

        // invalidate the map in order to show changes
        mapView.invalidate();

        MapController controller = mapView.getController();


        // Use the location manager through GPS
        locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
                0, this);

        //get the current location (last known location) from the location manager
        Location location = locManager
                .getLastKnownLocation(LocationManager.GPS_PROVIDER);



            //if location found display as a toast the current latitude and longitude
        if (location != null) {
            point = new GeoPoint((int)(location.getLatitude()*1E6),(int)(location.getLongitude() *1E6));
            Toast.makeText(
                    this,
                    "Current location:\nLatitude: " + location.getLatitude()
                            + "\n" + "Longitude: " + location.getLongitude(),
                    Toast.LENGTH_LONG).show();


            controller.animateTo(point);
            controller.setZoom(13);

        } else {

            Toast.makeText(this, "Cannot fetch current location!",
                    Toast.LENGTH_LONG).show();
        }


        // fetch the drawable - the pin that will be displayed on the map
        Drawable drawable = this.getResources().getDrawable(R.drawable.pin_custom);

        // create and add an OverlayItem to the MyItemizedOverlay list
        OverlayItem overlayItem = new OverlayItem(point, "", "");
        itemizedOverlay = new MapLocationOverlay(drawable,this);
        itemizedOverlay.addOverlay(overlayItem);

        // add the overlays to the map
        mapView.getOverlays().add(itemizedOverlay);
        mapView.invalidate();

        GestureDetector gd=new GestureDetector(this, new MyGestureDetector ());
        itemizedOverlay.setGestureDetector(gd);

        //when the current location is found – stop listening for updates (preserves battery)
        locManager.removeUpdates(this);
    }





    protected boolean isRouteDisplayed() {
        return false;

    }

    /* When the activity starts up, request updates */

    protected void onResume() {
        super.onResume();
        locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
                0, this);
    }


    protected void onPause() {
        super.onPause();
        locManager.removeUpdates(this); //activity pauses => stop listening for updates
    }

    public void onLocationChanged(Location location) {

    }



    public void onProviderDisabled(String provider) {

    }


    public void onProviderEnabled(String provider) {

    }


    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    public class MyGestureDetector  extends SimpleOnGestureListener {


        public boolean onSingleTapConfirmed(MotionEvent event) {

            // fetch the correspondent point from the map
            GeoPoint p = mapView.getProjection().fromPixels((int) event.getX(),(int) event.getY());

            // create an overlay item and clear all others
            OverlayItem o = new OverlayItem(p, null, null);
            itemizedOverlay.clear();
            itemizedOverlay.addOverlay(o);

            // add the overlay item
            mapView.getOverlays().clear();
            mapView.getOverlays().add(itemizedOverlay);
            mapView.invalidate();

            Geocoder geoCoder = new Geocoder(getBaseContext(),
                    Locale.getDefault());

            // get the address based on the coordinates
            try {
                List<Address> addresses = geoCoder.getFromLocation(p.getLatitudeE6() / 1E6, p.getLongitudeE6() / 1E6, 1);

                String addressString = "";
                if (addresses.size() > 0) {
                    for (int i = 0; i < addresses.get(0)
                            .getMaxAddressLineIndex(); i++)
                        addressString += addresses.get(0).getAddressLine(i)
                                + " - ";
                }

                Toast.makeText(getBaseContext(), addressString,
                        Toast.LENGTH_SHORT).show();

            } catch (IOException e) {
                e.printStackTrace();
            }

            return true;
        }

        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        public boolean onDown(MotionEvent e) {
            return false;
        }
    }


}

And class MapLocationOverlay:

public class MapLocationOverlay extends ItemizedOverlay<OverlayItem> {

       private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();
       private GestureDetector gestureDetector;

       private List<Pub> pubList;
       private Context context;



       public MapLocationOverlay(Context context, List<Pub> pubList, Drawable marker) {
          super(boundCenterBottom(marker));
          try{
              this.context = context;
              this.pubList = pubList;
              if (pubList == null) {
                  pubList = new ArrayList<Pub>();
              }
              populate();
          }
          catch(RuntimeException e){

          }

       }

       public MapLocationOverlay(Drawable defaultMarker, Context ctx) {
            super(boundCenterBottom(defaultMarker));

        }

       @Override
       protected OverlayItem createItem(int i) {
           try{
           Pub c=pubList.get(i);
              GeoPoint point =
                       new GeoPoint((int) (c.getLatitude() * 1e6), (int) (c.getLongitude() * 1e6));
              return new OverlayItem(point, c.getName(), null);
          }
          catch(RuntimeException e){

          }
          return mOverlays.get(i);
       }

       public void addOverlay(OverlayItem overlay) {
            mOverlays.add(overlay);
            populate();
        }

       public void clear() {

            mOverlays.clear();
            populate();
        }

       @Override
       public boolean onTap(final int index) {
           Pub c=pubList.get(index);
           final String name=c.getName();
           final String description=c.getDescription();
           final String street=c.getStreet();
         // BrewLocation brewLocation = brewLocations.get(index);
          AlertDialog.Builder builder = new AlertDialog.Builder(context);
          builder.setTitle("Visualizzare la nota "+name+"?")
                   .setPositiveButton("Si", new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog, int id) {
                         Intent pubDetails = new Intent(context, InfoPub.class);
                         pubDetails.putExtra("name", name);
                         pubDetails.putExtra("description", description);
                         pubDetails.putExtra("street", street);
                         context.startActivity(pubDetails);
                      }
                   }).setNegativeButton("No", new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog, int id) {
                         dialog.cancel();
                      }
                   });
          AlertDialog alert = builder.create();
          alert.show();

          return true; // we'll handle the event here (true) not pass to another overlay (false)
       }


        /**
         * Override this method to handle a "tap" on a balloon. By default, does nothing 
         * and returns false.
         * 
         * @param index - The index of the item whose balloon is tapped.
         * @return true if you handled the tap, otherwise false.
         */
        protected boolean onBalloonTap(int index) {
            return false;
        }

          @Override
            public boolean onTouchEvent(MotionEvent event, MapView mapView) {

                // when the user lifts its finger
                if (gestureDetector.onTouchEvent(event)) {
                    return true;
                }

                return false;
                }

            public GestureDetector getGestureDetector() {
                    return gestureDetector;
                }

            public void setGestureDetector(GestureDetector gestureDetector) {
                this.gestureDetector = gestureDetector;
            }

       @Override
       public int size() {
           //return pubList.size();
           return mOverlays.size();
       }



    }

Is not totally complete but should run, according the tutorial followed, unfortunately when I try to launch the activity the app crash with a fatal error.

This is the error stack:

10-13 17:25:56.109: E/AndroidRuntime(28215): FATAL EXCEPTION: main
10-13 17:25:56.109: E/AndroidRuntime(28215): java.lang.RuntimeException: Unable to start activity ComponentInfo{it.myapp.mymapapp/it.myapp.mymapapp.MyMap}: java.lang.NullPointerException
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1651)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.app.ActivityThread.access$1500(ActivityThread.java:117)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.os.Handler.dispatchMessage(Handler.java:99)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.os.Looper.loop(Looper.java:130)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.app.ActivityThread.main(ActivityThread.java:3687)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at java.lang.reflect.Method.invokeNative(Native Method)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at java.lang.reflect.Method.invoke(Method.java:507)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at dalvik.system.NativeStart.main(Native Method)
10-13 17:25:56.109: E/AndroidRuntime(28215): Caused by: java.lang.NullPointerException
10-13 17:25:56.109: E/AndroidRuntime(28215):    at com.google.android.maps.ItemizedOverlay.populate(ItemizedOverlay.java:312)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at it.myapp.mymapapp.utility.MapLocationOverlay.addOverlay(MapLocationOverlay.java:72)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at it.myapp.mymapapp.MyMap.onCreate(MyMap.java:89)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
10-13 17:25:56.109: E/AndroidRuntime(28215):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1615)
10-13 17:25:56.109: E/AndroidRuntime(28215):    ... 11 more

How Could I fix this? What's missing?

Was it helpful?

Solution

You are not initializing point in onCreate(), except if you get a valid lastKnownLocation().

This non initialized point is added to an OverlayItem, that is added to the ItemizedOverlay.

When Mapview try to get the Geopoint to draw Marker, it gets a null and bummmm!!

Just replace:

GeoPoint point;

by:

GeoPoint point = new Geopoint(0,0); 

and it will not crash anymore.

OTHER TIPS

Your createItem() implementation is rather strange:

  1. You catch a RuntimeException and do nothing with it. If nothing else, you should be logging the exception, particularly so long as you are having problems with your code.

  2. Your size() method is based off of mOverlays, yet you do not use mOverlays in createItem() (unless the mishandled RuntimeException occurs). Either use mOverlays consistently or get rid of it entirely.

Beyond that, something that ItemizedOverlay expects to not be null is indeed null. One possibility is the "snippet" (third parameter to the OverlayItem constructor), which you are setting to null. Another possibility is that c.getName() is returning null, and perhaps ItemizedOverlay needs the name to be non-null.

If nothing else, go back to the original code from that blog post, get that working, and then slowly modify it to have your desired functionality, testing as you go.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top