Larigyn
Larigyn

Reputation: 115

Android: Saving Map State in Google map

I used this code before but now i got some errors in Resuming the Map State. I got this code from David Gassner from its tutorial and now i want to use it again. im a little Bit Confused, I put some tossed message in order to trace. the LogCat report point the error in RESUME starting this line Anybody knows how to fix this?

map.animateCamera(update);          
map.setMapType(mgr.getSavedMapType())

heres the Code:

@Override
protected void onStop() {
    super.onStop();
    MapStateManager mgr = new MapStateManager(this);
    mgr.saveMapState(mMap);
    Toast.makeText(this, "Map State has been save?", Toast.LENGTH_SHORT).show();
}

@Override
protected void onResume() {
    super.onResume();
    MapStateManager mgr = new MapStateManager(this);
    CameraPosition position = mgr.getSavedCameraPosition();
    if (position != null) {
        CameraUpdate update = CameraUpdateFactory.newCameraPosition(position);
        Toast.makeText(this, "entering Resume State", Toast.LENGTH_SHORT).show();
        mMap.moveCamera(update);

        mMap.setMapType(mgr.getSavedMapType());
    }
}
public class MapStateManager {

    private static final String LONGITUDE = "longitude";
    private static final String LATITUDE = "latitude";
    private static final String ZOOM = "zoom";
    private static final String BEARING = "bearing";
    private static final String TILT = "tilt";
    private static final String MAPTYPE = "MAPTYPE";

    private static final String PREFS_NAME ="mapCameraState";

    private SharedPreferences mapStatePrefs;

    public MapStateManager(Context context) {
        mapStatePrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    }

    public void saveMapState(GoogleMap mapMie) {
        SharedPreferences.Editor editor = mapStatePrefs.edit();
        CameraPosition position = mapMie.getCameraPosition();

        editor.putFloat(LATITUDE, (float) position.target.latitude);
        editor.putFloat(LONGITUDE, (float) position.target.longitude);
        editor.putFloat(ZOOM, position.zoom);
        editor.putFloat(TILT, position.tilt);
        editor.putFloat(BEARING, position.bearing);
        editor.putInt(MAPTYPE, mapMie.getMapType());
        editor.commit();
    }

    public CameraPosition getSavedCameraPosition() {
        double latitude = mapStatePrefs.getFloat(LATITUDE, 0);
        if (latitude == 0) {
            return null;
        }
        double longitude = mapStatePrefs.getFloat(LONGITUDE, 0);
        LatLng target = new LatLng(latitude, longitude);

        float zoom = mapStatePrefs.getFloat(ZOOM, 0);
        float bearing = mapStatePrefs.getFloat(BEARING, 0);
        float tilt = mapStatePrefs.getFloat(TILT, 0);

        CameraPosition position = new CameraPosition(target, zoom, tilt, bearing);
        return position;
    }

    public int getSavedMapType() {
        return mapStatePrefs.getInt(MAPTYPE, GoogleMap.MAP_TYPE_NORMAL);
    }
}

Here is the error from the logcat. I only included the red lines.

> 01-07 12:51:46.145: E/AndroidRuntime(15770): FATAL EXCEPTION: main
01-07 12:51:46.145: E/AndroidRuntime(15770): java.lang.RuntimeException: Unable to resume activity {com.ourThesis.junieNegentien2015/com.ourThesis.junieNegentien2015.MainActivity}: java.lang.NullPointerException
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2936)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2965)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2400)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.ActivityThread.access$600(ActivityThread.java:162)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.os.Handler.dispatchMessage(Handler.java:107)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.os.Looper.loop(Looper.java:194)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.ActivityThread.main(ActivityThread.java:5371)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at java.lang.reflect.Method.invokeNative(Native Method)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at java.lang.reflect.Method.invoke(Method.java:525)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at dalvik.system.NativeStart.main(Native Method)
01-07 12:51:46.145: E/AndroidRuntime(15770): Caused by: java.lang.NullPointerException
01-07 12:51:46.145: E/AndroidRuntime(15770):    at com.ourThesis.junieNegentien2015.MainActivity.onResume(MainActivity.java:183)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1190)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.Activity.performResume(Activity.java:5213)
01-07 12:51:46.145: E/AndroidRuntime(15770):    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2923)
01-07 12:51:46.145: E/AndroidRuntime(15770):    ... 12 more

@Tim Castelijns, Below is the modified mode but still not working can you take a look?

private SupportMapFragment mapFragment;
    private GoogleMap map;  
    private Location mCurrentLocation;
    private GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); 
        setupMapIfNeeded();
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);

    }

    private void setupMapIfNeeded() {
        mapFragment = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));             
        if (mapFragment != null) {          
            mapFragment.getMapAsync(new OnMapReadyCallback()
            {
                @Override
                public void onMapReady(GoogleMap map) 
                {
                    loadMap(map);                                       
                }
            });
        } else 
        {
            Toast.makeText(this, "Error - Map Fragment was null!!", Toast.LENGTH_SHORT).show();
        }
    }

    protected void loadMap(GoogleMap googleMap) {
        map = googleMap;
        if (map != null) {
            // Map is ready
            Toast.makeText(this, "Map Fragment was loaded properly!", Toast.LENGTH_LONG).show();
            initListeners();            

            // map is loaded, trace your location
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addApi(LocationServices.API)               
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();
            connectClient();

            //calling resume state
            resumeState(map);

        } else {
            Toast.makeText(this, "Error - Map was null!!", Toast.LENGTH_SHORT).show();
        }
    }

    protected void connectClient() {
        // Connect the client.
        if (isGooglePlayServicesAvailable() && mGoogleApiClient != null) {
            mGoogleApiClient.connect();
            Toast.makeText(this, "Google API Client successfully connected", Toast.LENGTH_LONG).show();
        }
    }

    /*
     * Called when the Activity becomes visible.
    */
    @Override
    protected void onStart() {
        super.onStart();
        connectClient();
        }

    public void resumeState(GoogleMap googleMap) {      
        map = googleMap;
        MapStateManager mgr = new MapStateManager(this);
        CameraPosition position = mgr.getSavedCameraPosition();
        if (position != null) {
            CameraUpdate update = CameraUpdateFactory.newCameraPosition(position);
            Toast.makeText(this, "entering Resume State", Toast.LENGTH_LONG).show();
            map.moveCamera(update);

            map.setMapType(mgr.getSavedMapType());
        }
    }

    /*
     * Called when the Activity is no longer visible.
     */    
    @Override
    protected void onPause() {
        super.onPause();
        MapStateManager mgr = new MapStateManager(this);
        mgr.saveMapState(map);
        Toast.makeText(this, "Map State has been save?", Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onResume() {     
        super.onResume();       
        setupMapIfNeeded();
    }

    @Override
    public void onConnected(Bundle dataBundle) {
        // Display the connection status
        Location location = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if (location != null) {
            Toast.makeText(this, "GPS location was found!", Toast.LENGTH_SHORT).show();
            LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());
            CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 16);
            map.animateCamera(cameraUpdate);
            /*startLocationUpdates();*/
        } else {
            Toast.makeText(this, "Current location was null, enable GPS on your mobile!", Toast.LENGTH_SHORT).show();
        }
    }

    private void initListeners() {
        map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
        map.getUiSettings().setZoomControlsEnabled(true);
        map.setMyLocationEnabled(true);
        map.setOnMarkerClickListener(null);        
        map.setOnMapLongClickListener(null);
        map.setOnInfoWindowClickListener(null);
        map.setOnMapClickListener(null);
        map.setTrafficEnabled(true);
        map.setOnMapLongClickListener(this);
        map.setOnMapClickListener(this);
        map.setPadding(0, 80, 0, 0);

    }

Upvotes: 8

Views: 11209

Answers (3)

theshadowchild
theshadowchild

Reputation: 411

If you want to just save and restore the camera position between orientation changes, you could just save the CameraPosition instance itself on your saveInstanceState Bundle. CameraPosition implements ReflectedParcelable so this should work.

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    if (googleMap != null) {
        outState.putParcelable(STATE_KEY_MAP_CAMERA, googleMap.getCameraPosition());
    }
}

And to restored it do the following

if (savedInstanceState != null) {
    CameraUpdate cameraPos = CameraUpdateFactory.newCameraPosition(
        (CameraPosition)(savedInstanceState.getParcelable(STATE_KEY_MAP_CAMERA)));
    googleMap.moveCamera(cameraPos);
}

Upvotes: 3

Mikhail
Mikhail

Reputation: 37

mapFragment.setRetainInstance(true);You can use it at onCreate to save map fragment state

Upvotes: 2

Tim
Tim

Reputation: 43314

The problem is that your mMap is null when you are resuming, and then you cannot use mMap.moveCamera(); for example, which leads to your app crashing.

Solution for this is to check if the map needs to be set up before trying to use it again.

I slightly modified your code to check if the map needs to be set up in both onCreate and onResume. Note that I use onPause instead of onStop because it is the counterpart to onResume.

private GoogleMap mMap;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    setupMapIfNeeded();
}

private void setupMapIfNeeded() {
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    if (mMap == null) {
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }
}
@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    MapStateManager mgr = new MapStateManager(this);
    CameraPosition position = mgr.getSavedCameraPosition();
    if (position != null) {
        CameraUpdate update = CameraUpdateFactory.newCameraPosition(position);
        Toast.makeText(this, "entering Resume State", Toast.LENGTH_SHORT).show();
        mMap.moveCamera(update);

        mMap.setMapType(mgr.getSavedMapType());
    }
}

@Override
protected void onPause() {
    super.onPause();
    MapStateManager mgr = new MapStateManager(this);
    mgr.saveMapState(mMap);
    Toast.makeText(this, "Map State has been save?", Toast.LENGTH_SHORT).show();
}

@Override
protected void onResume() {
    super.onResume();
    setupMapIfNeeded();
}

MapstateManager is exactly the same.

public class MapStateManager {

    private static final String LONGITUDE = "longitude";
    private static final String LATITUDE = "latitude";
    private static final String ZOOM = "zoom";
    private static final String BEARING = "bearing";
    private static final String TILT = "tilt";
    private static final String MAPTYPE = "MAPTYPE";

    private static final String PREFS_NAME ="mapCameraState";

    private SharedPreferences mapStatePrefs;

    public MapStateManager(Context context) {
        mapStatePrefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
    }

    public void saveMapState(GoogleMap mapMie) {
        SharedPreferences.Editor editor = mapStatePrefs.edit();
        CameraPosition position = mapMie.getCameraPosition();

        editor.putFloat(LATITUDE, (float) position.target.latitude);
        editor.putFloat(LONGITUDE, (float) position.target.longitude);
        editor.putFloat(ZOOM, position.zoom);
        editor.putFloat(TILT, position.tilt);
        editor.putFloat(BEARING, position.bearing);
        editor.putInt(MAPTYPE, mapMie.getMapType());
        editor.commit();
    }

    public CameraPosition getSavedCameraPosition() {
        double latitude = mapStatePrefs.getFloat(LATITUDE, 0);
        if (latitude == 0) {
            return null;
        }
        double longitude = mapStatePrefs.getFloat(LONGITUDE, 0);
        LatLng target = new LatLng(latitude, longitude);

        float zoom = mapStatePrefs.getFloat(ZOOM, 0);
        float bearing = mapStatePrefs.getFloat(BEARING, 0);
        float tilt = mapStatePrefs.getFloat(TILT, 0);

        CameraPosition position = new CameraPosition(target, zoom, tilt, bearing);
        return position;
    }

    public int getSavedMapType() {
        return mapStatePrefs.getInt(MAPTYPE, GoogleMap.MAP_TYPE_NORMAL);
    }
}

Upvotes: 12

Related Questions