1

I have a map fragment in my Main Activity that on my onMapReady I am adding let's say 300 markers. The markers are divided into 5 categories, each category saved in a List category1(2,3,4,5) = new ArrayList. I have a button that filters the markers by category by setting them visible or not according to the users options from an alert dialog.

for (Marker marker : category1) {
                marker.setVisible(true);.....

Everything works exactly as it should until the screen configuration changes. One solution that I found to keep the visible markers on rotation was to add in my onCreate

if (savedInstanceState == null) {
    mapFragment.setRetainInstance(true);}

This works for keeping the current selection but then when I try to filter again nothing changes. The state of the map fragment remains with the markers that I filtered before the configuration changed.

On the other hand if I am not using the mapFragment.setRetainInstance(true); each time the configuration changes ALL the markers are added again on the fragment, filtering works again but i have to re filter each time.

How can I add all the markers once, and then hide/show them according to the category filter, keep the visible ones between screen rotation and filter them again starting from the last state they were?

UPDATE

Here is what I have (I tried to add only the relevant code)

    Boolean mSetCameraPosition;
    Boolean initialMarkers;
    Boolean checkBox1Checked, checkBox2Checked, checkBox3Checked,     checkBox4Checked, checkBox5Checked;
    private int mapTypeSelected;
    CheckBox cbAllDay, cbBefore12, cbBetween1216, cbBetween1620, ccbAfter20;
    AlertDialog dialog;
    List<Marker> firstCategoryList = new ArrayList<>();
    List<Marker> secondCategoryList = new ArrayList<>();
    List<Marker> thirdCategoryList = new ArrayList<>();
    List<Marker> fourthCategoryList = new ArrayList<>();
    List<Marker> fifthCategoryList = new ArrayList<>();


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


        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            checkLocationPermission();
        }


        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);


        if (savedInstanceState == null) {
            mapTypeSelected = GoogleMap.MAP_TYPE_NORMAL;
            mSetCameraPosition = true;
            mapFragment.setRetainInstance(true);
            initialMarkers = true;


        } else {
            mapTypeSelected = savedInstanceState.getInt("the_map_type", GoogleMap.MAP_TYPE_NORMAL);
            mSetCameraPosition = false;
            initialMarkers = false;

            checkBox1Checked = savedInstanceState.getBoolean("checkBox1");
            checkBox2Checked = savedInstanceState.getBoolean("checkBox2");
            checkBox3Checked = savedInstanceState.getBoolean("checkBox3");
            checkBox4Checked = savedInstanceState.getBoolean("checkBox4");
            checkBox5Checked = savedInstanceState.getBoolean("checkBox5");

  @Override
    public void onMapReady(GoogleMap googleMap) {

        mMap = googleMap;
        if (mSetCameraPosition) {
            initialLocation(TOULOUSE_LAT, TOULOUSE_LNG, 12);

        }
        mMap.setMapType(mapTypeSelected);

 if (initialMarkers) {
            addMarkers2Map();
        }

  public void addMarkers2Map() {

        // Markers location

        LatLng marker1 = new LatLng(43.607044, 1.450307);
        LatLng marker2= new LatLng(43.571505, 1.417759);
        LatLng marker3= new LatLng(43.607469, 1.447162);
        LatLng marker4= new LatLng(43.600723, 1.455917);
        LatLng marker5= new LatLng(43.604892, 1.476562);
        LatLng marker6= new LatLng(43.604496, 1.474924);
        LatLng marker7= new LatLng(43.604781, 1.474502);

        // Markers All day long
        firstCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker1).title("First Place ").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 8.30 - 22.30")));

        // Markers Before 12 PM
        secondCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker2).title("Second Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 10.30 - 11.30")));

        // Markers Between 12-16
        thirdCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker3).title("Third Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 15.30 - 16.30")));
        thirdCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker4).title("Fourth Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 15.00 - 16.00")));

        // Markers Between 16-20
        fourthCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker5).title("Fifth Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 15.30 - 16.30")));
        fourthCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker6).title("Sixth Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 16.30 - 17.30")));
        fourthCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker7).title("Seventh Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 18.30 - 19.30")));
        fourthCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker8).title("Eighth Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 17.30 - 18.30\nHH:21.30 - 22.30")));


        // Markers After 20
        fifthCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker8).title("Eighth Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 17.30 - 18.30\nHH:21.30 - 22.30")));
        fifthCategoryList.add(mMap.addMarker(new MarkerOptions().position(marker1).title("First Place").icon(BitmapDescriptorFactory.fromResource(R.drawable.beer_marker)).snippet("HH: 8.30 - 22.30")));


  public void filterTheMarkers(View view) {


        if (dialog == null){
        AlertDialog.Builder builder;
        builder = new AlertDialog.Builder(this);
        LayoutInflater inflater = this.getLayoutInflater();
        @SuppressLint("InflateParams") View checkBoxView = inflater.inflate(R.layout.markers_filtering, null);
        builder.setView(checkBoxView);
        cbAllDay = (CheckBox) checkBoxView.findViewById(R.id.checkBox1);
        if (checkBox1Checked != null) {
            cbAllDay.setChecked(checkBox1Checked);

        }
        cbBefore12 = (CheckBox) checkBoxView.findViewById(R.id.checkBox2);
        if (checkBox2Checked != null) {
            cbBefore12.setChecked(checkBox2Checked);

        }
        cbBetween1216 = (CheckBox) checkBoxView.findViewById(R.id.checkBox3);
        if (checkBox3Checked != null) {
            cbBetween1216.setChecked(checkBox3Checked);

        }
        cbBetween1620 = (CheckBox) checkBoxView.findViewById(R.id.checkBox4);
        if (checkBox4Checked != null) {
            cbBetween1620.setChecked(checkBox4Checked);

        }
        ccbAfter20 = (CheckBox) checkBoxView.findViewById(R.id.checkBox5);
        if (checkBox5Checked != null) {
            ccbAfter20.setChecked(checkBox5Checked);

        }

        dialog = builder.create();


    }

        dialog.show();
    }

  public void displaySelectedMarkers(View view) {

        dialog.dismiss();
        Log.i("TAG", "All Day " + cbAllDay.isChecked() + " Before 12 " + cbBefore12.isChecked() + " Between 12-16 " + cbBetween1216.isChecked() + " Between 16-20" + cbBetween1620.isChecked() + " After 20 " + ccbAfter20.isChecked());
        //according these check boxes status execute your code to show/hide markers


        if (cbAllDay.isChecked() && cbBefore12.isChecked() && cbBetween1216.isChecked() && cbBetween1620.isChecked() && ccbAfter20.isChecked()) {
            // show all markers
            for (Marker marker : firstCategoryList) {
                marker.setVisible(true);
            }
            for (Marker marker : secondCategoryList) {
                marker.setVisible(true);
            }
            for (Marker marker : thirdCategoryList) {
                marker.setVisible(true);
            }
            for (Marker marker : fourthCategoryList) {
                marker.setVisible(true);
            }
            for (Marker marker : fifthCategoryList) {
                marker.setVisible(true);
            }
        } else if (cbAllDay.isChecked() && !cbBefore12.isChecked() && !cbBetween1216.isChecked() && !cbBetween1620.isChecked() && !ccbAfter20.isChecked()) {
            // show only All Day Markers
            for (Marker marker : firstCategoryList) {
                marker.setVisible(true);
            }
            for (Marker marker : secondCategoryList) {
                marker.setVisible(false);
            }
            for (Marker marker : thirdCategoryList) {
                marker.setVisible(false);
            }
            for (Marker marker : fourthCategoryList) {
                marker.setVisible(false);
            }
            for (Marker marker : fifthCategoryList) {
                marker.setVisible(false);
            }
        }
//....and it goes like this for a while until I finish all the possibilities

  @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("the_map_type", mapTypeSelected);

        outState.putBoolean("checkBox1", cbAllDay.isChecked());
        outState.putBoolean("checkBox2", cbBefore12.isChecked());
        outState.putBoolean("checkBox3", cbBetween1216.isChecked());
        outState.putBoolean("checkBox4", cbBetween1620.isChecked());
        outState.putBoolean("checkBox5", ccbAfter20.isChecked());

    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        savedInstanceState.get("the_map_type");

        checkBox1Checked = savedInstanceState.getBoolean("checkBox1");
        checkBox2Checked = savedInstanceState.getBoolean("checkBox2");
        checkBox3Checked = savedInstanceState.getBoolean("checkBox3");
        checkBox4Checked = savedInstanceState.getBoolean("checkBox4");
        checkBox5Checked = savedInstanceState.getBoolean("checkBox5");
Alex Simion
  • 93
  • 1
  • 14
  • I would recommend that you use `onSavedInstanceState` method to save the state of your application when the configuration changes (as is normal) and restore the state in `onCreate`. This means you have to remember what filters were selected and set them again and you have to remember what markers were opened and open them again. – Ali May 02 '16 at 12:28
  • I have updated my question with part of the code that I consider relevant, can you give me an example as how you would do it? Thanks in advance. – Alex Simion May 02 '16 at 15:55

2 Answers2

5

You could handle orientation changes yourself in your manifest:

<activity android:name=".MyActivity"
          android:configChanges="orientation|screenSize"
          android:label="@string/app_name">

(from Handling Runtime Changes)

That way, your Activity isn't recreated when the orientation or screen size changes. You'll have to handle things like layout switching yourself though if you have overrides for landscape/portrait.

ByteWelder
  • 5,464
  • 1
  • 38
  • 45
  • I have added this code inside the Manifest but nothing really happened. I have updated my question so you could see what I have up till now... – Alex Simion May 02 '16 at 15:59
  • I would like to add that 90 % of the code for the app will be in my MainActivity. So this solution that you suggested could be the simplest and the best one for me . After reading the Handling Runtime Changes that you suggested it is not really clear for me when android:configChanges="orientation|screenSize" should be used. I mean what are the disadvantages of using this solution ? I don't understand exactly what does this mean" Handling the configuration change yourself can make it much more difficult to use alternative resources" Thanks in advance for your patience! – Alex Simion May 02 '16 at 16:18
  • I used this android:configChanges="orientation|screenSize" in a test app that I have and it does exactly what I want so my only request is to give me some exemples with the disadvantages of using this. Why is everybody suggesting to use the onSaveInstanceState or Shared Preferences, or different fragments to save the data when this does it so easily. Thanks again! – Alex Simion May 02 '16 at 16:30
  • The disadvantages are that you have to handle things like layout changes yourself. For example: having a `/res/drawable-land` and `/res/drawable-port` folder won't automatically be loaded on rotation unless you inflate them yourself. – ByteWelder May 02 '16 at 17:14
  • @KenVanHoeylandt List firstCategoryList (and other marker lists) wont cause memory leak after orientation change ? Because marker has icon ? – blackkara May 02 '16 at 17:16
  • `onSaveInstanceState` is also a good solution though: this way you can store your Fragment/Activity state and restore it on layout recreation. – ByteWelder May 02 '16 at 17:16
  • Yeah, onSaveInstanceState gave me a lot of issues till now. I will go with your first suggestion as it is simple and working fine for my app. Thanks:-) – Alex Simion May 03 '16 at 07:38
  • I have tried many ways and this is the simplest and shortest, worked very well for me. Thank you. – RobertoFRey May 22 '18 at 02:17
0

It seems that calling setRetainInstance(true); on the fragment that holds the map retains everything on the map through orientation changes etc, without having to worry about saving and recovering state.

M. Usman Khan
  • 3,689
  • 1
  • 59
  • 69