I've been trying to use MapView inside a ViewPager fragment and I've encountered a weird bug. MapView keeps glitching like it's trying to re-render and stretching the map weirdly; however, while using zoom/gestures, it's fine. The moment it stops moving it starts glitching again. On Nexus 7 SDK 22 emulator it works fine, while it seems to fail on most of the other emulators/physical devices. It seems it's a hardware rather than a SDK problem. I also tried to just put a SupportMapFragment inside the ViewPager and it behaves the exact same way. Disabling hardware acceleration in the manifest reduces the problem, but it doesn't eliminate it. Country names keep flickering, and the whole screen has a black flicker every few seconds, rather than the stretchy/glitchy bug that happens without the hardware acceleration workaround.
MapViewFragment
public class RealisedVisitsMapFragment extends Fragment implements OnMapReadyCallback {
private FragmentRealisationVisitsMapBinding binding;
public static RealisedVisitsMapFragment newInstance(LocalDate date) {
RealisedVisitsMapFragment fragment = new RealisedVisitsMapFragment();
return fragment;
}
private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKey";
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentRealisationVisitsMapBinding.inflate(inflater);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
}
binding.mapView.onCreate(mapViewBundle);
binding.mapView.getMapAsync(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Bundle mapViewBundle = outState.getBundle(MAPVIEW_BUNDLE_KEY);
if (mapViewBundle == null) {
mapViewBundle = new Bundle();
outState.putBundle(MAPVIEW_BUNDLE_KEY, mapViewBundle);
}
binding.mapView.onSaveInstanceState(mapViewBundle);
}
@Override
public void onResume() {
super.onResume();
binding.mapView.onResume();
}
@Override
public void onStart() {
super.onStart();
binding.mapView.onStart();
}
@Override
public void onStop() {
super.onStop();
binding.mapView.onStop();
}
@Override
public void onMapReady(GoogleMap map) {
map.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
@Override
public void onPause() {
binding.mapView.onPause();
super.onPause();
}
@Override
public void onDestroy() {
binding.mapView.onDestroy();
super.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
binding.mapView.onLowMemory();
}
}
PagerAdapter
public class VisitsFragmentAdapter extends FragmentStateAdapter {
public VisitsFragmentAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
public VisitsFragmentAdapter(@NonNull Fragment fragment) {
super(fragment);
}
@NonNull
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return SupportMapFragment.newInstance();
case 1:
return new RealisedVisitsMapFragment();
default:
return null;
}
}
@Override
public int getItemCount() {
return 2;
}
}
Hosting fragment function for setting up the viewpager
private void setupViewPager() {
VisitsFragmentAdapter pagerAdapter = new VisitsFragmentAdapter(getChildFragmentManager(), getLifecycle());
binding.vpVisitsRealization.setUserInputEnabled(false);
binding.vpVisitsRealization.setAdapter(pagerAdapter);
binding.vpVisitsRealization.requestTransparentRegion(binding.vpVisitsRealization);
new TabLayoutMediator(binding.tabLayoutRealization, binding.vpVisitsRealization, (this::setTextByPosition)).attach();
}
Resolved by removing viewpager altogether and manually inflating fragments.