'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 |
