Search code examples
androidgoogle-mapsgeojson

Show large geojson file in android google maps


I am trying to show a geojson layer to Google Map. The code is as follows. The geojson file is stored locally in my raw folder. The file has 286 features (around 15MB). Hence, reading this file and displaying it is consuming more time. Initially, I was getting out of memory error, which is removed by setting large heap as true in the manifest file. How can I load this file quickly (currently, its taking a minute or more)? I am wondering if there is some other efficient method to do this. After this, I will also have other tasks of getting features and displaying some properties.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
    mapFragment.getMapAsync(this);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;
    mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(myanmar, 5.25f));
    new MyAsyncTask().execute();
}

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

    ProgressDialog pd;
    GeoJsonLayer layer;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pd = new ProgressDialog(MapsActivity.this);
        pd.setMessage("Loading Data");
        pd.show();
    }

    @Override
    protected Void doInBackground(Void... voids) {
        try {
            layer = new GeoJsonLayer(mMap, R.raw.myanmar, getApplicationContext());
        } catch (Exception e) {
            Log.d("Error is : ", e.toString());
        }
        return null;
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        pd.cancel();
        layer.addLayerToMap();
     }
}

A very small portion of my geojson file is as follows:

{
 "type": "FeatureCollection",
 "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
 "features": [
{ "type": "Feature", "properties": { "ID_3": 193, "NAME_3": "Chaung-U" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 95.348327636718807, 21.878610610961914 ], [ 95.297210693359432, 21.860000610351676 ], [ 95.286926269531307, 21.853612899780387 ], [ 95.276092529296989, 21.850000381469727 ], [ 95.265823364257926, 21.84832954406744 ], [ 95.257217407226676, 21.846940994262695 ] ] ] ] } },
{ "type": "Feature", "properties": { "ID_3": 199, "NAME_3": "Myaung" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ 95.376281738281193, 21.708541870117301 ], [ 95.375259399414119, 21.703050613403434 ], [ 95.370529174804801, 21.681390762329102 ], [ 95.367752075195313, 21.664720535278434 ], [ 95.366699218750114, 21.658369064331055 ], [ 95.362762451171875, 21.649999618530273 ] ] ] ] } }
]}

I try to divide the file into multiple small file units and run separate async tasks in parallel, each processing a separate file:

for (int i = 1; i < 3; i++) {
        new MyAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,i);
}

AsyncTask:

public class MyAsyncTask extends AsyncTask <Integer, Void, GeoJsonLayer> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected GeoJsonLayer doInBackground(Integer... integers) {
        int i = integers[0];
        try {
            GeoJsonLayer layer = null;
            switch (i) {
                case 1:
                    layer = new GeoJsonLayer(mMap, R.raw.small_1,
                            getApplicationContext());
                    break;
                case 2:
                    layer = new GeoJsonLayer(mMap, R.raw.small_2,
                            getApplicationContext());
                    break;
                //other cases
            }
            for (GeoJsonFeature feature : layer.getFeatures()) {
                geoJsonFeatures.put(Integer.parseInt(feature.getProperty("ID_3")), feature);
            }
            return layer;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    protected void onPostExecute(GeoJsonLayer layer) {
        super.onPostExecute(layer);
        layer.addLayerToMap();
    }
}

Is this suggested? Doing so, the time is reduced as compared to earlier, but still not yet fast considering the user experience factor.


Solution

  • Finally, solved the issue by reducing the size of the geojson file. Used http://mapshaper.org/ , an online tool, that provides you with the options to reduce the size, yet preserving the shape. Used it to obtain simplified file (nearly 300KB) and bang, the loading completes within few seconds. Hope this helps someone facing the same issue.