title: Restoring MapView's state on rotate and on back
body: <p><strong>Background</strong></p>
  
  <p>I have a larger application in which I had/have several problems with new Google Maps API. I tried to describe it <a href="https://stackoverflow.com/questions/16171619/markers-disapearing-from-mapview-v2-in-fragment-on-back">in a different question</a> but since it seems too complex I decided to start a new project, as simple as possible and try to reproduce problems. So here it is.</p>
  
  <p><strong>The situation</strong></p>
  
  <p>I'm using <code>Fragments</code> and want to put <code>MapView</code> inside. I don't want to use <code>MapFragment</code>. The sample project I prepared may be not very beautiful but I tried to make it as simple as possible and it had to contain some elements (again simplified) from the original app.
  I have one <code>Activity</code> and my custom <code>Fragment</code> with <code>MapView</code> in it, added programatically. The <code>Map</code> contains some points/<code>Markers</code>. After clicking on a <code>Marker</code> the <code>InfoWindow</code> is shown and clicking on it causes next <code>Fragment</code> being shown (with <code>replace()</code> function) in content. </p>
  
  <p><strong>The problems</strong></p>
  
  <p>There are two issues I have:</p>
  
  <ol>
  <li><p>When the <code>Map</code> with <code>Markers</code> is displayed screen rotation causes <code>Class not found when unmarshalling</code> error with my custom <code>MyMapPoint</code> class - I have no idea why and what it means.</p></li>
  <li><p>I click the <code>Marker</code> and then <code>InfoWindow</code>. After this I press hardware back button. Now I can see the <code>Map</code> but with no <code>Markers</code> and centered in <code>0,0</code> point.</p></li>
  </ol>
  
  <p><strong>The code</strong></p>
  
  <p>MainActivity</p>
  
  <pre><code>public class MainActivity extends FragmentActivity {
  
      private ArrayList&lt;MyMapPoint&gt; mPoints = new ArrayList&lt;MyMapPoint&gt;();
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_main);     
  
          if (savedInstanceState == null) {
              mPoints.add(new MyMapPoint(1, new LatLng(20, 10), 
                  "test point", "description", null));            
              mPoints.add(new MyMapPoint(2, new LatLng(10, 20), 
                  "test point 2", "second description", null));
  
              Fragment fragment = MyMapFragment.newInstance(mPoints);
              getSupportFragmentManager().beginTransaction()
                  .add(R.id.contentPane, fragment).commit();
          }
      }
  }
  </code></pre>
  
  <p>activity_main.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;FrameLayout 
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/contentPane"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent" /&gt;
  </code></pre>
  
  <p>map_fragment.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="vertical" &gt;
  
      &lt;com.google.android.gms.maps.MapView
          xmlns:map="http://schemas.android.com/apk/res-auto"
          android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent" /&gt;
  
  &lt;/LinearLayout&gt;
  </code></pre>
  
  <p>MyMapFragment</p>
  
  <pre><code>public class MyMapFragment extends Fragment implements
      OnInfoWindowClickListener {
  
      public static final String KEY_POINTS = "points";
  
      private MapView mMapView;
      private GoogleMap mMap;
      private HashMap&lt;MyMapPoint, Marker&gt; mPoints = 
          new HashMap&lt;MyMapPoint, Marker&gt;();
  
      public static MyMapFragment newInstance(ArrayList&lt;MyMapPoint&gt; points) {
          MyMapFragment fragment = new MyMapFragment();
          Bundle args = new Bundle();
          args.putParcelableArrayList(KEY_POINTS, points);
          fragment.setArguments(args);
          return fragment;
      }
  
      @Override
      public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          mMapView.onSaveInstanceState(outState);
          MyMapPoint[] points = mPoints.keySet().toArray(
              new MyMapPoint[mPoints.size()]);
          outState.putParcelableArray(KEY_POINTS, points);
      }
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
  
          if (savedInstanceState == null) {
              Bundle extras = getArguments();
              if ((extras != null) &amp;&amp; extras.containsKey(KEY_POINTS)) {
                  for (Parcelable pointP : extras.getParcelableArrayList(KEY_POINTS)) {
                      mPoints.put((MyMapPoint) pointP, null);
                  }
              }
          } else {
              MyMapPoint[] points = (MyMapPoint[]) savedInstanceState
                  .getParcelableArray(KEY_POINTS);
              for (MyMapPoint point : points) {
                  mPoints.put(point, null);
              }
          }
      }
  
      @Override
      public View onCreateView(LayoutInflater inflater, 
          ViewGroup container, Bundle savedInstanceState) {
          View layout = inflater.inflate(R.layout.map_fragment, container, false);
          mMapView = (MapView) layout.findViewById(R.id.map);
          return layout;
      }
  
      @Override
      public void onActivityCreated(Bundle savedInstanceState) {
          super.onActivityCreated(savedInstanceState);
          mMapView.onCreate(savedInstanceState);
          setUpMapIfNeeded();
          addMapPoints();
      }
  
      @Override
      public void onPause() {
          mMapView.onPause();
          super.onPause();
      }
  
      @Override
      public void onResume() {
          super.onResume();
          setUpMapIfNeeded();
          mMapView.onResume();
      }
  
      @Override
      public void onDestroy() {
          mMapView.onDestroy();
          super.onDestroy();
      }
  
      public void onLowMemory() {
          super.onLowMemory();
          mMapView.onLowMemory();
      };
  
      private void setUpMapIfNeeded() {
          if (mMap == null) {
              mMap = ((MapView) getView().findViewById(R.id.map)).getMap();
              if (mMap != null) {
                  setUpMap();
              }
          }
      }
  
      private void setUpMap() {
          mMap.setOnInfoWindowClickListener(this);
          addMapPoints();
      }
  
      private void addMapPoints() {
          if (mMap != null) {
              HashMap&lt;MyMapPoint, Marker&gt; toAdd = 
                  new HashMap&lt;MyMapPoint, Marker&gt;();
              for (Entry&lt;MyMapPoint, Marker&gt; entry : mPoints.entrySet()) {
                  Marker marker = entry.getValue();
                  if (marker == null) {
                      MyMapPoint point = entry.getKey();
                      marker = mMap.addMarker(point.getMarkerOptions());
                      toAdd.put(point, marker);
                  }
              }
              mPoints.putAll(toAdd);
          }
      }
  
      @Override
      public void onInfoWindowClick(Marker marker) {
          Fragment fragment = DetailsFragment.newInstance();
          getActivity().getSupportFragmentManager().beginTransaction()
              .replace(R.id.contentPane, fragment)
              .addToBackStack(null).commit();
      }
  
      public static class MyMapPoint implements Parcelable {
          private static final int CONTENTS_DESCR = 1;
  
          public int objectId;
          public LatLng latLng;
          public String title;
          public String snippet;
  
          public MyMapPoint(int oId, LatLng point, 
              String infoTitle, String infoSnippet, String infoImageUrl) {
              objectId = oId;
              latLng = point;
              title = infoTitle;
              snippet = infoSnippet;
          }
  
          public MyMapPoint(Parcel in) {
              objectId = in.readInt();
              latLng = in.readParcelable(LatLng.class.getClassLoader());
              title = in.readString();
              snippet = in.readString();
          }
  
          public MarkerOptions getMarkerOptions() {
              return new MarkerOptions().position(latLng)
                  .title(title).snippet(snippet);
          }
  
          @Override
          public int describeContents() {
              return CONTENTS_DESCR;
          }
  
          @Override
          public void writeToParcel(Parcel dest, int flags) {
              dest.writeInt(objectId);
              dest.writeParcelable(latLng, 0);
              dest.writeString(title);
              dest.writeString(snippet);
          }
  
          public static final Parcelable.Creator&lt;MyMapPoint&gt; CREATOR = 
              new Parcelable.Creator&lt;MyMapPoint&gt;() {
              public MyMapPoint createFromParcel(Parcel in) {
                  return new MyMapPoint(in);
              }
  
              public MyMapPoint[] newArray(int size) {
                  return new MyMapPoint[size];
              }
          };
  
      }
  }
  </code></pre>
  
  <p>If you need to take a look at any other file - let me know. <a href="http://www.scio.pl/maptest.tgz" rel="nofollow noreferrer">Here</a> you can find a complete project, you just have to put your own Maps API KEY in <code>AndroidManifest.xml</code> file.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>I managed to make the example even more simple and updated the code above.</p>