Show large geojson file in android google maps

岁酱吖の 提交于 2020-01-14 09:11:07

问题


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.


回答1:


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.




回答2:


You should use json streaming either with Gson or Jackson.For details have a look at Jackson Vs. Gson, Streaming JSON Parsing Performance Test: Jackson vs. GSON or JSON.simple vs GSON vs Jackson vs JSONP




回答3:


I had put code for how to deserialise geojson code. But i have never tried Google Map before. Maybe you might come up with another question ?

Below i show you how to deserialised your huge geojson file with GSON Streaming.

GeoJSON.java

public class GeoJSON {

    @SerializedName("type")
    private String type;
    @SerializedName("features")
    private List<Features> features;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }


    public List<Features> getFeatures() {
        return features;
    }

    public void setFeatures(List<Features> features) {
        this.features = features;
    }
}

Features.java

public class Features {

    @SerializedName("type")
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

Convert json to pojo class

private void readGeoJSON() {
        try {
            InputStream is = getAssets().open("geo.json");

            JsonReader reader = new JsonReader(new InputStreamReader(is, "UTF-8"));
            Gson gson = new GsonBuilder().create();

            GeoJSON geoJSON = new GeoJSON();
            ArrayList<Features> features = new ArrayList<>();

            reader.beginObject();
            while (reader.hasNext()){
                String key = reader.nextName();
                if(key.equals("type")){
                    geoJSON.setType(reader.nextString());
                }else if(key.equals("features")){
                    // read array
                    reader.beginArray();
                    while (reader.hasNext()) {
                        Features o = gson.fromJson(reader, Features.class);
                        features.add(o);
                    }
                    reader.endArray();
                }else{
                    reader.skipValue(); //avoid some unhandle events
                }

                geoJSON.setFeatures(features);
            }

            reader.endObject();
            reader.close();


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

With this approach we are loading all the objects to memory but one by one and not the whole file at once.

Assume i store geo.json file in asset folder. This is how you can deserialised your local geo.json and i had tested the code, it worked. You may need to add in for other fields. Hope it might solve your memory overhead issue.



来源:https://stackoverflow.com/questions/42266565/show-large-geojson-file-in-android-google-maps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!