Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ASYNC Task to load map pins

Tags:

android

I've been successful at adding map pins to my map overlay but it loads slow and moving around the map is sluggish. I am thinking it is when it is downloading the map pins from the server. The pins are only about 20-30 kb in size, but at times are may be 25 pins to add. I have already tried to add the pins in the background but it will break the app. What can I do to add the pins in the background without affecting performance?

I get the location from map when the user touches the map and executes this ASYNC task.

    private class mapStations extends AsyncTask<Void, Void, JSONObject> {

    @Override
    protected JSONObject doInBackground(Void... arg0) {

        JSONObject obj = null;
        try {
            obj = new JSONObject(API.nearByStations(pxLat, pxLng, 0));

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

        return obj;
    }

    @Override
    protected void onPostExecute(JSONObject details) {
        String tag = "mapStations";
        JSONArray stations;
        Drawable d = null;
        try {
            mapOverlays = mapView.getOverlays();
            mapOverlays.clear();
            stations = details.getJSONArray("stations");

            for (int j = 0; j < stations.length(); j++) {
                JSONObject jsonObject = stations.getJSONObject(j);
                Log.i(tag, "url: " + jsonObject.getString("logo"));
                try {

                    Bitmap staticImage = BitmapFactory
                            .decodeStream((InputStream) new URL(jsonObject.getString("logo"))
                                    .getContent());
                    d = new BitmapDrawable(staticImage);

                } catch (MalformedURLException e) {
                    Log.e(tag, e.toString());
                    e.printStackTrace();
                } catch (IOException e) {
                    Log.e(tag, e.toString());
                    e.printStackTrace();
                }
                add(jsonObject.getDouble("lat"),
                        jsonObject.getDouble("lng"), d);
            }

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

    }
}

public void add(double lat, double lng, Drawable d) {

    mapOverlays = mapView.getOverlays();
    if(d.equals(null)){
        Log.i(tag, "d was null");
        d = this.getResources().getDrawable(R.drawable.androidmarker);
    }

    itemizedOverlay = new MapsOverlay(d);

    GeoPoint point = new GeoPoint((int) (lat * 1e6), (int) (lng * 1e6));
    OverlayItem overlayitem = new OverlayItem(point, "", "");

    itemizedOverlay.addOverlay(overlayitem);
    mapOverlays.add(itemizedOverlay);
}

This is the logcat from adding the points in the doinbackground. It doesn't happen every time but it does happen. I can't seem to reproduce when it happens either. Sometime it happens when I zoom out, sometimes it happens when I move around the map. I had similar question about this here Android MapView JSON Array Adding Array of points but I ended up moving it to the post execute. Like I mentioned before it takes awhile to load the pins. I am kind of at a loss write now. I have been working on this all day.

    [12-23 13:46:27.246: E/AndroidRuntime(1359): Uncaught handler: thread main exiting due to uncaught exception
12-23 13:46:27.286: E/AndroidRuntime(1359): java.util.ConcurrentModificationException
12-23 13:46:27.286: E/AndroidRuntime(1359):     at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at com.google.android.maps.OverlayBundle.draw(OverlayBundle.java:41)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at com.google.android.maps.MapView.onDraw(MapView.java:476)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.View.draw(View.java:6535)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1531)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1529)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.View.draw(View.java:6538)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.widget.FrameLayout.draw(FrameLayout.java:352)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1531)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1529)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1529)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1529)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1529)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.View.draw(View.java:6538)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.widget.FrameLayout.draw(FrameLayout.java:352)][1]
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1531)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.drawChild(ViewGroup.java:1529)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1258)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.View.draw(View.java:6538)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.widget.FrameLayout.draw(FrameLayout.java:352)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1830)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewRoot.draw(ViewRoot.java:1349)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewRoot.performTraversals(ViewRoot.java:1114)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1633)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.os.Handler.dispatchMessage(Handler.java:99)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.os.Looper.loop(Looper.java:123)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at android.app.ActivityThread.main(ActivityThread.java:4363)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at java.lang.reflect.Method.invokeNative(Native Method)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at java.lang.reflect.Method.invoke(Method.java:521)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
12-23 13:46:27.286: E/AndroidRuntime(1359):     at dalvik.system.NativeStart.main(Native Method)
like image 723
Brandon Wilson Avatar asked Dec 23 '11 17:12

Brandon Wilson


3 Answers

In order to prevent the user for inadvertently editing the list while it is already being edited. I decided to place dialog in the onPreExecute() while the pins are being loaded. This has prevented the user from touching the map while new pins are being added. Until I can find time to come up with a better idea on how to prevent this from happening this will have to do.

I clear the overlays from the map before I start adding new pins, this is completed during onPreExecute(). On the onPostExecute() I dismiss the dialog and invalidate() the map. This will draw the new map pins on the map after adding them to the list.

@Override
    protected void onPreExecute() {
        Log.i(tag, "AsyncTask Started");
        dialog.show();
        mapOverlays = mapView.getOverlays();
        mapOverlays.clear();
    }

@Override
    protected void onPostExecute(Void args) {
        mapView.invalidate();
        dialog.dismiss();
        Log.i(tag, "AsyncTask Post");
    }
like image 184
Brandon Wilson Avatar answered Nov 10 '22 00:11

Brandon Wilson


The ConcurrentModificationException usually happens when you're trying to modify the list while iterating it. To overcome the exception you can use a special list type named CopyOnWriteArrayList. It safely lets you add and remove items from a list during iteration. Hope this helps.

like image 22
Egor Avatar answered Nov 10 '22 00:11

Egor


Your app is moving slowly because the onPostExecute function is done on the UI thread. The bitmap decoding that you are doing here is causing the UI to be slow because this is network intensive and you are doing it on the UI thread. I would suggest getting all of the bitmaps on the doInBackground thread and then actually adding them to the map on onPostExecute method. The only thing you should actually do on the UI thread is the add method.

like image 41
Brian Griffey Avatar answered Nov 10 '22 02:11

Brian Griffey