I have a use case where a list and a map view share quite the same code base and show the same data. So I cannot separate them by using ListFragment and MapFragment as parent.
So I made a fragment that contains both views:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"/>
<com.google.android.gms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
The user can toggle between list and map view. This works very well despite the fact that the map view cannot retain its markers on configuration changes. When the screen is rotated, the map view get's its initial state without markers and without zoom. All markers that where previously added are gone. When I used MapFragment I did not have this problem, it kind of retained itself.
Stripped down code:
public class ListAndMapFragment extends Fragment {
private MapView mapView;
public ListAndMapFragment() {}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle arguments) {
super.onCreateView(inflater, container, arguments);
View root = inflater.inflate(R.layout.fragment_pillar_list, container, false);
mapView = (MapView) root.findViewById(R.id.mapView);
if (arguments == null) {
mapView.onCreate(null);
MapsInitializer.initialize(this.getActivity());
}
return root;
}
private GoogleMap getMap() {
return mapView.getMap();
}
@Override
public void onResume() {
mapView.onResume();
super.onResume();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
Any ideas how to address this problem? One solution would be to replace all markers. However I would like to know if there is another approach.
Now there is all sorts of documentation that show how to use a MapFragment to display a MapView. Unfortunately if you are looking to just include a MapView inside of a Fragment, that documentation does you no good.
In Android, the fragment is the part of Activity that represents a portion of the User Interface (UI) on the screen. It is the modular section of the android activity that is very helpful in creating UI designs that are flexible in nature and auto-adjustable based on the device screen size.
A GoogleMap must be acquired using getMapAsync (OnMapReadyCallback). The MapView automatically initializes the maps system and the view. According to this, the more correct way to initialize GoogleMap is using getMapAsync.
To nest a fragment, simply call getChildFragmentManager () on the Fragment in which you want to add a fragment. This returns a FragmentManager that you can use like you normally do from the top-level activity to create fragment transactions. For example, here’s some code that adds a fragment from within an existing Fragment class:
Marker
object cannot be retained through configuration changes because it doesn't implement Parcelable
or Serializable
interface.
However, you can persist MarkerOptions
object because it is Parcelable and then recreate your Marker
s from it. You can have a class field of type MarkerOptions
for each of your Marker
s and then re-populate the map on configuration changes (for example in onSaveInstanceState
):
mapView.getMap().addMarker(MyMarkerOptions);
Another way would be to save your Marker
s in a HashMap and re-use them on configuration changes.
Here is another full example
that uses Parcelable LatLng
points to persist Markers
.
The example works so when adding a marker it also adds the corresponding coordinates to an ArrayList
as LatLng
object. Then on configuration change, the ArrayList
gets saved to a Bundle
object in onSaveInstanceState
and the LatLng
objects get retrieved in onCreate
.
OP's note:
So I went with the solution to implement onSaveInstanceState
and drop setRetainInstance(true)
. The benefit is that I can retain the map myself. However the disadvantage is that the map has to be fully initialized on each config change which makes the app slow for 1 or 2 seconds on e.g. screen rotation. But I am fine with this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With