'Android app - Google maps location markers disappearing from Map fragment

I am very new to Android development. This is my first attempt at creating an app. I have created a tabbed navigation app, with 4 fragments to navigate between: Home, Search, Map and Account fragments from the MainActivity. I have used a SupportMapFragment within my MapsFragment to display the map. Upon visiting the MapsFragment the map displays and zooms in on my Current location and highlights certain important locations, retrieved from a Firebase instance, with markers.

Everything works as expected when I first launch the app and visit the Map Fragment. I am zoomed into my current location and I see all required markers. The problem arises when I switch to a different fragment from that point. When I navigate to the Home, Search or Account fragment and then return to the Map fragment, none of the location markers are visible anymore. I can still see my current location and get zoomed into it on opening the Map fragment but the other markers disappear.

I originally thought it was to do with the fragment being recreated everytime I navigate to another fragment as I use .replace(container, fragment) to change the fragment based on which button was clicked from the bottom navigation bar. But I observed that the Map fragment would load my current location and zoom into it correctly, so the loadMap() function gets executed but somehow the markers don't appear. If i restart the app, the markers behave correctly the first time I open the Map fragment.

Any help on how to keep the markers showing on the Map when I return to it after navigating to other fragments will be greatly appreciated. Thank you!

Here is a preview of my MapsFragment.java:

public class MapsFragment extends Fragment {
    private SupportMapFragment supportMapFragment;
    private AutocompleteSupportFragment autocompleteSupportFragment;
    private FusedLocationProviderClient client;
    private Geocoder geocoder;
    private ArrayList<String> mPostCodes;
    private ArrayList<Marker> searchMarker;
    private DatabaseReference locationRef;
    private DatabaseReference businessRef;
    private String apiKey;


    public MapsFragment() {
        // Required empty public constructor
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        // Initialize Map fragment
        supportMapFragment = (SupportMapFragment)
                getChildFragmentManager().findFragmentById(R.id.google_map);

        // initialize Places client
        apiKey = getString(R.string.map_key);
        if(!Places.isInitialized()){
            Places.initialize(requireActivity(), apiKey);
        }
        PlacesClient placesClient = Places.createClient(requireActivity());

        // Initialize AutoComplete search bar and set autocomplete parameters
        autocompleteSupportFragment = (AutocompleteSupportFragment)
                getChildFragmentManager().findFragmentById(R.id.autocomplete_fragment);
        autocompleteSupportFragment.setTypeFilter(TypeFilter.ADDRESS);
        autocompleteSupportFragment.setLocationBias(RectangularBounds.newInstance(
                new LatLng(55.836229, -4.252612),
                new LatLng(55.897463, -4.325364)));
        autocompleteSupportFragment.setCountries("UK");
        autocompleteSupportFragment.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.NAME, Place.Field.LAT_LNG));

        // initialize search marker list
        searchMarker = new ArrayList<Marker>();

        // Initialize client to get user's last location on device
        client = LocationServices.getFusedLocationProviderClient(requireActivity());

        // Initialize geocoder to convert business postcodes to latlng coordinates
        mPostCodes = new ArrayList<>();
        geocoder = new Geocoder(requireActivity());

        // Get business locations
        locationRef = FirebaseDatabase.getInstance().getReference("Business Locations");
        locationRef.addListenerForSingleValueEvent(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                if(snapshot.exists()){
                    for(DataSnapshot locationSnapshot : snapshot.getChildren()){
                        BusinessLocation location = locationSnapshot.getValue(BusinessLocation.class);
                        mPostCodes.add(location.getPostCode());
                    }
                }
            }
            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Log.i("Location error", "Error retrieving location: ", error.toException().getCause());
            }
        });

        // initialize reference to business table
        businessRef = FirebaseDatabase.getInstance().getReference("Businesses");

        // render the map
        loadMap();
    }

    private void loadMap() {
        if (ActivityCompat.checkSelfPermission(requireActivity(),
                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            Task<Location> task = client.getLastLocation();

            task.addOnSuccessListener(new OnSuccessListener<Location>() {
                @Override
                public void onSuccess(Location location) {
                    if(location != null){
                        supportMapFragment.getMapAsync(new OnMapReadyCallback() {
                            @Override
                            public void onMapReady(@NonNull GoogleMap googleMap) {

                                // autocomplete place search
                                autocompleteSupportFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
                                    @Override
                                    public void onError(@NonNull Status status) {
                                        Log.i("AutoComplete error", "error status: " + status);
                                    }

                                    @Override
                                    public void onPlaceSelected(@NonNull Place place) {
                                        LatLng placeLatLng = place.getLatLng();

                                        MarkerOptions placeOptions = new MarkerOptions().position(placeLatLng)
                                                .title("search")
                                                .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE));

                                        if(!searchMarker.isEmpty()){
                                            Marker searchedMarker = searchMarker.get(0);
                                            searchMarker.remove(searchedMarker);
                                            searchedMarker.remove();
                                        }

                                        final Marker marker  = googleMap.addMarker(placeOptions);
                                        searchMarker.add(marker);
                                        googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(placeLatLng, 10));
                                    }
                                });

                                LatLng myLatLng = new LatLng(location.getLatitude(),
                                        location.getLongitude());

                                // show current location
                                if (ActivityCompat.checkSelfPermission(requireActivity(),
                                        Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                                    googleMap.setMyLocationEnabled(true);
                                    googleMap.getUiSettings().setZoomControlsEnabled(true);
                                    googleMap.getUiSettings().setCompassEnabled(true);
                                }

                                // show markers for all businesses on database
                                for(String code : mPostCodes){
                                    try{
                                        Address address = geocoder.getFromLocationName(code, 1).get(0);
                                        LatLng latLng = new LatLng(address.getLatitude(), address.getLongitude());

                                        MarkerOptions options = new MarkerOptions().position(latLng);
                                        googleMap.addMarker(options);
                                    }catch (IOException e){
                                       Toast.makeText(requireActivity(), e.getMessage(), Toast.LENGTH_LONG).show();
                                    }
                                }
                                googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(myLatLng, 10));
                            }
                        });
                    }
                }
            });
        }else {
            ActivityCompat.requestPermissions(requireActivity(),
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 44);
        }
    }

    private ActivityResultLauncher<String> mPermissionResult = registerForActivityResult(
            new ActivityResultContracts.RequestPermission(),
            result -> {
                if(result){
                    loadMap();
                }
            }
    );
}

Here is my fragment_maps.xml file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".fragments.MapsFragment">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/google_map"
        android:name="com.google.android.gms.maps.SupportMapFragment"/>

    <fragment
        android:id="@+id/autocomplete_fragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"/>

</RelativeLayout>

And here is my MainActivity.kt file:

class MainActivity : AppCompatActivity() {

    private val homeFragment = HomeFragment()
    private val searchFragment = SearchFragment()
    private val mapFragment = MapsFragment()
    private val accountFragment = AccountFragment()
    private val guestAccountFragment = GuestAccountFragment()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        replaceFragment(homeFragment)

        bottom_navigation.setOnItemSelectedListener {
            when (it.itemId) {
                R.id.id_home -> replaceFragment(homeFragment)
                R.id.id_search -> replaceFragment(searchFragment)
                R.id.id_map -> replaceFragment(mapFragment)
                R.id.id_account -> {
                    if(FirebaseAuth.getInstance().currentUser == null){
                        replaceFragment(guestAccountFragment)
                    }else {
                        replaceFragment(accountFragment)
                    }
                }
            }
            true
        }

    }

    private fun replaceFragment(fragment : Fragment){
        if(fragment != null){
            val transaction = supportFragmentManager.beginTransaction()
            transaction.replace(R.id.fragment_container, fragment)
            transaction.commit()
        }
    }
}


Solution 1:[1]

It happening beacuse your map fragment is "dying" after replacing on new fragment. Try this solution:

First of all you need add in your main activity all required fragments which can be called:

getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container_view, fragment1)
                .add(R.id.fragment_container_view, fragment2)
                .add(R.id.fragment_container_view, fragment3)
                .commit();

After adding you can change them by calling this code:

getSupportFragmentManager().beginTransaction()
                    .show(fragment2)
                    .hide(fragment1)
                    .commit();

Code was writen on Java but I think there is no problem

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Snuiper228