When an android map activity is started it may take quite a while to be up and running. What is worse, it needs some time to load, which disrupts smooth user interaction when started from a list item, a button or an icon in your app. It may take up to seconds for the map activity to appear. We haven’t found a way to speed things up, but there is a way to achieve a much better user experience.
Our solution is to let the Activity render without the MapView first. It will start up quickly and display a message that the map is loading. Then add and initialize the MapView in a seperate thread.
We use OSMDroid. The same approach can be used for Google Maps.
Suppose you have the following layout:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <org.osmdroid.views.MapView android:id="@+id/mapview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> <TextView android:id="@+id/status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:background="#50000000" android:gravity="center" android:padding="16dp" android:textColor="#ffffffff" android:visibility="gone" /> </RelativeLayout> |
Now completely remove the MapView and replace it with a container ViewGroup. We’ll use FrameLayout here. Add a string resource containing the message for the loading map.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/mapContainer" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/loading" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/loading_map" /> </FrameLayout> <TextView android:id="@+id/status" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:background="#50000000" android:gravity="center" android:padding="16dp" android:textColor="#ffffffff" android:visibility="gone" /> </RelativeLayout> |
In onCreate, use a delayed thread to add the MapView. We apply a delay of 100 ms. Experiment with this value. If it’s too low our approach has no effect at all. If it’s too high we unnecessarily delay our rendering.
mapContainer = (FrameLayout) findViewById(R.id.mapContainer); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { mMapView = new MapView(SetRouteActivity.this, 256); mMapView.setTileSource(TileSourceFactory.MAPNIK); mMapView.setBuiltInZoomControls(true); mMapView.setMultiTouchControls(true); mapController = SetRouteActivity.this.mMapView.getController(); mMapView.setMaxZoomLevel(17); mapController.setZoom(15); org.osmdroid.views.MapView.LayoutParams mapParams = new org.osmdroid.views.MapView.LayoutParams( org.osmdroid.views.MapView.LayoutParams.MATCH_PARENT, org.osmdroid.views.MapView.LayoutParams.MATCH_PARENT, null, 0, 0, 0); mapContainer.addView(mMapView, mapParams); // Initialization of Overlays, location, etc. goes here. } }, 100); |
Note that the OSMDroid MapView constructor takes the tile size in pixels.
So the Activity starts immediately resulting in a reactive user experience. Then the MapView renders and becomes visible when it’s ready.
One thought on “Starting an Android Activity containing a MapView takes forever”
Comments are closed.