Question

I have an app that puts a marker down and saves it. I am also using mylocationoverlay to show the users current position. The app works most of the time and during testing it seems to work fine. However when I use it on my phone it crashes if I try to have too many pins at once (over 500). I was wondering if there was a limit to the number of overlays we're allowed to have or if theres something else that's wrong with my program

Here is my Map class, I add the pins in the reload function (its gathered from a webserver) and the mylocationoverlay is in the oncreate method.

PS, I noticed that everytime it calls the function reload, the overlays from before don't go away. should I call removeAllViews before adding in the pins again? Thanks

public class Maps extends MapActivity {

    private MapView mapView = null;
    private MyLocationOverlay myLocationOverlay = null;

    ProgressDialog progressDialog;
    private ArrayList<Pins> mList;
    final public static int[] pincolorstar = { R.drawable.pinredstar,
            R.drawable.pinlitebluestar, R.drawable.pinblackstar,
            R.drawable.pindarkbluestar, R.drawable.pingreenstar,
            R.drawable.pinlitegreenstar, R.drawable.pinorangestar,
            R.drawable.pinyellowstar, R.drawable.pinwhitestar,
            R.drawable.pinpurplestar };
    static boolean setSatellite, setHybrid = false;

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        myLocationOverlay.disableMyLocation();
    }

    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        myLocationOverlay.enableMyLocation();
    }

    @Override
    protected void onCreate(Bundle icicle) {
        // TODO Auto-generated method stub

        super.onCreate(icicle);
        try {
            setContentView(R.layout.maps);
        } catch (Exception e) {
            e.printStackTrace();
        }
        final SharedPreferences prefs = getSharedPreferences("Settings", 0);
        final int hour = prefs.getInt("Hour_Range", 4);
        mapView = (MapView) findViewById(R.id.mapView);
        myLocationOverlay = new MyLocationOverlay(Maps.this, mapView);
        mapView.getOverlays().add(myLocationOverlay);
        new Reload().execute();
        Button done = (Button) findViewById(R.id.btnDone);
        done.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                finish();
            }
        });
        Button change = (Button) findViewById(R.id.btnChangeTime);
        change.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                final int hour = prefs.getInt("Hour_Range", 4);
                LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View layout = inflater.inflate(R.layout.your_dialog,
                        (ViewGroup) findViewById(R.id.relativeLayoutMaps));

                final SeekBar seekBar = (SeekBar) layout
                        .findViewById(R.id.seekBarChangeTime);
                final TextView ChangeTexthour = (TextView) layout
                        .findViewById(R.id.tVChangeableTime);
                ChangeTexthour.setText(prefs.getString("Hour_notification",
                        "Only most recent positions"));
                seekBar.setProgress(hour);
                OnSeekBarChangeListener yourSeekBarListener = new OnSeekBarChangeListener() {

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onProgressChanged(SeekBar seekBar,
                            int progress, boolean fromUser) {
                        ChangeTexthour
                                .setText(getResources()
                                        .getString(
                                                R.string.showlocationsforthelastxhours1)
                                        + " "
                                        + progress
                                        + " "
                                        + getResources()
                                                .getString(
                                                        R.string.showlocationsforthelastxhours2));

                    }
                };

                seekBar.setOnSeekBarChangeListener(yourSeekBarListener);

                AlertDialog.Builder builder = new AlertDialog.Builder(Maps.this)
                        .setView(layout)
                        .setPositiveButton(
                                getResources().getString(R.string.Cancel), null)
                        .setNegativeButton("Set",
                                new DialogInterface.OnClickListener() {

                                    @Override
                                    public void onClick(DialogInterface dialog,
                                            int which) {

                                        SharedPreferences.Editor editor = prefs
                                                .edit();
                                        editor.putString(
                                                "Hour_notification",
                                                getResources()
                                                        .getString(
                                                                R.string.showlocationsforthelastxhours1)
                                                        + " "
                                                        + seekBar.getProgress()
                                                        + " "
                                                        + getResources()
                                                                .getString(
                                                                        R.string.showlocationsforthelastxhours2));
                                        editor.putInt("Hour_Range",
                                                seekBar.getProgress());
                                        editor.commit();
                                        new Reload().execute();
                                    }
                                });
                AlertDialog alertDialog = builder.create();
                alertDialog.show();

            }
        });
        Button displayChange = (Button) findViewById(R.id.btnDisplayChange);
        displayChange.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                AlertDialog.Builder builder = new AlertDialog.Builder(Maps.this)
                        .setMessage("Map Display Mode")
                        .setPositiveButton("Map",
                                new DialogInterface.OnClickListener() {

                                    @Override
                                    public void onClick(DialogInterface dialog,
                                            int which) {
                                        setSatellite = false;
                                        setHybrid = false;
                                        new Reload().execute();
                                    }
                                })
                        .setNeutralButton("Satellite",
                                new DialogInterface.OnClickListener() {

                                    @Override
                                    public void onClick(DialogInterface dialog,
                                            int which) {
                                        setSatellite = true;
                                        setHybrid = false;
                                        new Reload().execute();

                                    }
                                })
                        .setNegativeButton("Hybrid",
                                new DialogInterface.OnClickListener() {

                                    @Override
                                    public void onClick(DialogInterface dialog,
                                            int which) {
                                        setHybrid = true;
                                        setSatellite = false;
                                        new Reload().execute();
                                    }
                                });
                AlertDialog alertDialog = builder.create();
                alertDialog.show();
            }
        });

    }

    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }

    private class Pins {
        private String name;
        private String time;
        private String id;
        private boolean mostrecent;
        private Double longitude;
        private Double latitude;

        public Pins(String time, String id, String mostrecent,
                Double longitude, Double latitude) {
            this.time = time;
            this.id = id;

            this.longitude = longitude;
            this.latitude = latitude;
            boolean active = false;
            if (mostrecent.equals("1"))
                active = true;
            else
                active = false;
            this.mostrecent = active;
        }

        public String getName() {
            return name;
        }

        public String getTime() {
            return time;
        }

        public String getId() {
            return id;
        }

        public boolean getMostRecent() {
            return mostrecent;
        }

        public Double getLongitude() {
            return longitude;
        }

        public Double getLatitude() {
            return latitude;
        }

        public void setName(String name) {
            this.name = name;
        }

    }

    public class Reload extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            final SharedPreferences prefs = getSharedPreferences("Settings", 0);
            final int hour = prefs.getInt("Hour_Range", 4);
            int followsize = 0;
            for (int i = 0; i < ImTracking.ping.length; i++) {
                followsize += ImTracking.ping[i];
            }
            String[] ids = new String[followsize];
            int counter = 0;
            for (int i = 0; i < ImTracking.ping.length; i++) {
                if (ImTracking.ping[i] == 1) {
                    ids[counter] = ImTracking.pList.get(i).getid();
                    counter++;
                }
            }
            JSONArray users = new JSONArray(Arrays.asList(ids));

            HttpParams httpParams = new BasicHttpParams();
            // 30seconds and it stops
            HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
            HttpConnectionParams.setSoTimeout(httpParams, 30000);
            DefaultHttpClient httpclient = new DefaultHttpClient(httpParams);
            HttpPost httpost = new HttpPost(
                    "https://iphone-radar.com/gps/gps_locations_fetch");

            JSONObject holder = new JSONObject();

            try {
                holder.put("userids", users);
                holder.put("range", hour);
                Calendar c = Calendar.getInstance();
                TimeZone tz = c.getTimeZone();
                Date now = new Date();
                int offsetFromUtc = tz.getOffset(now.getTime()) / 1000;
                holder.put("timezone", offsetFromUtc);
                StringEntity se = new StringEntity(holder.toString());
                httpost.setEntity(se);
                httpost.setHeader("Accept", "application/json");
                httpost.setHeader("Content-type", "application/json");

                ResponseHandler responseHandler = new BasicResponseHandler();
                String response = httpclient.execute(httpost, responseHandler);
                org.json.JSONObject obj = new org.json.JSONObject(response);
                JSONArray tracking_users = obj.getJSONArray("d");
                ArrayList<Pins> mList = new ArrayList<Pins>();
                int minLat = Integer.MAX_VALUE;
                int maxLat = Integer.MIN_VALUE;
                int minLon = Integer.MAX_VALUE;
                int maxLon = Integer.MIN_VALUE;
                for (int i = 0; i < tracking_users.length(); i++) {
                    JSONObject user = tracking_users.getJSONObject(i);
                    Pins pin = new Pins(user.getString("time"),
                            user.getString("user_id"),
                            user.getString("most_recent"),
                            user.getDouble("longitude"),
                            user.getDouble("latitude"));
                    maxLat = (int) Math.max(user.getDouble("latitude") * 1E6,
                            maxLat);
                    minLat = (int) Math.min(user.getDouble("latitude") * 1E6,
                            minLat);
                    maxLon = (int) Math.max(user.getDouble("longitude") * 1E6,
                            maxLon);
                    minLon = (int) Math.min(user.getDouble("longitude") * 1E6,
                            minLon);

                    mList.add(pin);
                }
                mapView.setSatellite(setSatellite);
                mapView.setStreetView(setHybrid);
                List<Overlay> mapOverlays = mapView.getOverlays();

                for (int i = 0; i < mList.size(); i++) {
                    Drawable drawable = null;
                    for (int k = 0; k < ImTracking.pList.size(); k++) {
                        if (mList.get(i).getId()
                                .equals(ImTracking.pList.get(k).getid())) {
                            mList.get(i).setName(
                                    ImTracking.pList.get(k).getName());
                            if (mList.get(i).getMostRecent()) {
                                drawable = Maps.this.getResources()
                                        .getDrawable(
                                                pincolorstar[ImTracking.pList
                                                        .get(k).getPosition()]);

                            } else {
                                drawable = Maps.this
                                        .getResources()
                                        .getDrawable(
                                                ImTracking.pincolors[ImTracking.pList
                                                        .get(k).getPosition()]);
                            }
                        }
                    }

                    HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(
                            drawable, mapView);
                    GeoPoint myPoint = new GeoPoint((int) (mList.get(i)
                            .getLatitude() * 1E6), (int) (mList.get(i)
                            .getLongitude() * 1E6));
                    OverlayItem overlayitem = new OverlayItem(myPoint, mList
                            .get(i).getName(), mList.get(i).getTime());
                    itemizedoverlay.addOverlay(overlayitem);
                    mapOverlays.add(itemizedoverlay);
                }

                MapController mc = mapView.getController();
                mc.zoomToSpan(Math.abs(maxLat - minLat),
                        Math.abs(maxLon - minLon));

                mc.animateTo(new GeoPoint((maxLat + minLat) / 2,
                        (maxLon + minLon) / 2));

            } catch (Exception e) {
                e.printStackTrace();
            }
            progressDialog.dismiss();
            return null;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog = ProgressDialog.show(Maps.this, "",
                    "Updating Data...");
        }
    }
}
Was it helpful?

Solution

You should not have 500 overlays each with only one pin. What you you should have is only two overlays. One is MyLocationOverlay the other is the ItemizedOverlay.

The ItemizedOverlay can hold more than one pin. You should take the line below out of the loop.

mapOverlays.add(itemizedoverlay);

See also OverlayItem setMarker() to set the Drawable for individual item so you don't have to create multiple overlays.

To be more precise:


// take this out from the loop since you only need one 
HelloItemizedOverlay itemizedoverlay = new HelloItemizedOverlay(drawable, mapView);

for (int i = 0; i < mList.size(); i++) {
    ... the rest of the code


    GeoPoint myPoint = new GeoPoint((int) (mList.get(i)
            .getLatitude() * 1E6), (int) (mList.get(i)
                    .getLongitude() * 1E6));
    OverlayItem overlayitem = new OverlayItem(myPoint, mList
            .get(i).getName(), mList.get(i).getTime());

    // set the drawable here for each item instead of setting it for each Overlay
    overlayitem.setMarker(drawable);
    itemizedoverlay.addOverlay(overlayitem);

}

// take this one out the loop. ItemizedOverlay can handle multiple items
// you don't have to create multiple ItemizedOverlay for each pin
mapOverlays.add(itemizedoverlay);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top