Note that there are some explanatory texts on larger screens.

plurals
  1. PORestoring MapView's state on rotate and on back
    primarykey
    data
    text
    <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>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload