5

i have around 11000 markers in markerarray list, when i try to load in map it blocks my UI, even when i use Thread and RunOnUi thread, is there any other better way i can try ??

 Thread t = new Thread(new Runnable() {

                @Override
                public void run() {
                    for (int i = 0; i < list.size(); i++) {

                        markerOptionList.add(new MarkerOptions().position(
                                new LatLng(Double.parseDouble(list.get(i)
                                        .getLatitude()), Double
                                        .parseDouble(list.get(i)
                                                .getLangtitude()))).title(
                                list.get(i).getName() + "~"
                                        + list.get(i).getCity() + "~"
                                        + list.get(i).getSector() + "~"
                                        + String.valueOf(false)));
                    }

                    getActivity().runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            addMarker();
                        }
                    });

                }
            });
            t.start();

add marker is my method where i added marker in map

Kindly suggest better way to implement Thanks in advance

Madhu
  • 1,780
  • 23
  • 47
  • You shouldn't add all the markers at once. Rather add them on demand. You can do that by using your zoom level and the visible parts of the map to determine which markers to load at which time. So at a lower zoom level you would group your markers by area or something similar and only show one marker for that area and as you zoom increases, increase the amount for that specific area. – the-ginger-geek Jun 29 '15 at 06:04
  • 1
    I think AsyncTask in Android may help you – jeet parmar Jun 29 '15 at 06:11
  • Create MarkerOption object outside for loop. MarkerOptions markerOptions=new MarkerOptions(); – jinkal Jun 29 '15 at 06:18
  • Asynctask with Progressdialog helps me – Madhu Jun 29 '15 at 06:43

2 Answers2

5

With such amount of markers as you mentioned (11000) it is highly advisable to use Marker Clustering. You can read more about it on: https://developers.google.com/maps/documentation/android-api/utility/marker-clustering

If you still want to do this without Marker Clustering there is a simple trick that can improve user experience.

As adding a marker modifies UI - it has to be done in main UI thread. Adding too much of them at one time blocks the main thread so that the application does not respond to any user actions while it is busy with adding markers. The end user may feel like the application has hung or stopped or it can even lead to ANR

The trick is to add the markers gradually, leaving some breaks for main thread to handle other actions, so that the application remains responsive for whole the time.

I would suggest such approach:

public class DrawMarkersTask extends AsyncTask<Void, MarkerOptions, Void> {
    protected void onPreExecute() {
        // this method executes in UI thread
        googleMap.clear(); // you can clear map here for example
    }

    @Override
    protected Void doInBackground(Void... params) {
        // this method executes in separate background thread
        // you CANT modify UI here
        for (int i = 0; i < list.size(); i++) {
            // prepare your marker here
            MarkerOptions markerOptions = new MarkerOptions().position(
                            new LatLng(Double.parseDouble(list.get(i)
                                    .getLatitude()), Double
                                    .parseDouble(list.get(i)
                                            .getLongtitude()))).title(
                            list.get(i).getName() + "~"
                                    + list.get(i).getCity() + "~"
                                    + list.get(i).getSector() + "~"
                                    + String.valueOf(false)));

            publishProgress(markerOptions); // pass it for the main UI thread for displaying
            try {
                Thread.sleep(50); // sleep for 50 ms so that main UI thread can handle user actions in the meantime
            } catch (InterruptedException e) {
                // NOP (no operation)
            }
        }
        return null;
    }

    protected void onProgressUpdate(MarkerOptions... markerOptions) {
        // this executes in main ui thread so you can add prepared marker to your map
        googleMap.addMarker(markerOptions[0]);
    }

    protected void onPostExecute(Void result) {
        // this also executes in main ui thread
    }
}

Note that DrawMarkersTask must be inner class of your Activity so it has direct access to UI. If you would like to make it separate class follow this: android asynctask sending callbacks to ui

Then you draw markers without blocking main thread like this:

DrawMarkersTask drawMarkersTask = new DrawMarkersTask();
drawMarkersTask.execute();

NOTE: This is just a trick. It has nothing to do with reducing or optimising complexity of this problem it just hides it from user by spreading operations in time. Yet still such approach is sometimes an acceptable compromise.

Krzysiek
  • 7,895
  • 6
  • 37
  • 38
  • This approach is working great for me. I set `Thread.sleep(1)`, and still allows for plenty of user interaction as markers are loading. Thank you for the comprehensive answer. – seekingStillness Mar 24 '19 at 19:09
2

Loading 11000 makers is a very heavy workload for the device. Even you can add all of them to the map, when you zoom out, you will probably face the same problem. There is a official Google article about various advanced marker management techniques. Use one of them to show only necessary markers instead of all of them.

Joshua
  • 5,901
  • 2
  • 32
  • 52
  • @Madhu It does not require you to remove any markers. You can show them on different zoom level. Even you can show them all at once, they will still overlap each other. – Joshua Jun 29 '15 at 06:49