A tab within my view pager contains a map view is showing some unexpected behaviour. For some reason whenever I go to a different tab and return to the map view tab, all 4 pins within my map view appear when only 2 of them are supposed to appear. Does anyone know why this has happened? What can be done in order to prevent this from happening?
Stage 1 (flicked the top switch)
Stage 2 (flicked the bottom switch)
Stage 3 (switching to a different tab, then returning back to the map tab)
Java class
public class FragmentCentralPark extends android.support.v4.app.Fragment implements OnMapReadyCallback {
public FragmentCentralPark() {
// Required empty constructor
}
GoogleMap mGoogleMap;
MapView mMapView;
SwitchCompat swt0;
SwitchCompat swt1;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_centralpark, container, false);
mMapView = (MapView) v.findViewById(R.id.map_centralpark);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this); //this is important
swt0 = (SwitchCompat) v.findViewById(R.id.switch0_map_centralpark);
swt1 = (SwitchCompat) v.findViewById(R.id.switch1_map_centralpark);
return v;
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
mGoogleMap.setBuildingsEnabled(true);
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
swt0.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
initMap0(isChecked);
}
});
swt1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
initMap1(isChecked);
}
});
initMap0(swt0.isChecked());
initMap1(swt1.isChecked());
// Add markers and move the camera
LatLng centralpark_museum1 = new LatLng(40.785407, -73.957145);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum1)
);
LatLng centralpark_museum2 = new LatLng(40.782993, -73.958985);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum2)
);
// Updates the location and zoom level of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(40.780437, -73.981063), 16);
mGoogleMap.animateCamera(cameraUpdate);
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
private void initMap0(boolean isChecked){
if (isChecked) {
mGoogleMap.setMapStyle(new MapStyleOptions(getResources()
.getString(R.string.style_json)));
} else {
mGoogleMap.setMapStyle(null);
}
}
private void initMap1(boolean isChecked){
if (isChecked) {
mGoogleMap.clear();
// Add markers and move the camera
LatLng centralpark__theatre1 = new LatLng(40.780287, -73.968832);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_theatre1)
);
LatLng centralpark__theatre2 = new LatLng(40.780437, -73.981063);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_theatre2)
);
// Updates the location and zoom level of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(40.780437, -73.981063), 16);
mGoogleMap.animateCamera(cameraUpdate);
} else {
mGoogleMap.clear();
// Add markers and move the camera
LatLng centralpark_museum1 = new LatLng(40.785407, -73.957145);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum1)
);
LatLng centralpark_museum2 = new LatLng(40.782993, -73.958985);
mGoogleMap.addMarker(new MarkerOptions()
.position(centralpark_museum2)
);
// Updates the location and zoom level of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(40.780437, -73.981063), 16);
mGoogleMap.animateCamera(cameraUpdate);
}
}
}
Related
I have the problem which I write in the title
Here are the 2 codes from MapsActivity and fragment
#Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
map.setMyLocationEnabled(true);
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location location) {
// redraw the marker when get location update.
LatLng latlng = new LatLng(location.getLatitude(), location.getLongitude());
map.addMarker(new MarkerOptions().position(latlng).title("Marker").snippet(Float.toString(location.getSpeed())));
map.moveCamera(CameraUpdateFactory.newLatLng(latlng));
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 15, locationListener);
}
}
Fragment Map
public class Tab2Map extends Fragment implements OnMapReadyCallback {
GoogleMap map;
public Tab2Map() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v=inflater.inflate(R.layout.fragment_tab2, container, false);
return v;
}
#Override
public void onViewCreated(View view,#Nullable Bundle savedInstanceState){
super.onViewCreated(view,savedInstanceState);
SupportMapFragment mapFragment=(SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.fragment);
mapFragment.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
}
}
Ηow can I put the marker from MapsActivity into the fragment because it's the only way to print it in map.App has Action Bar Tabs and the map can be displayed only through fragment?
Call this method in onMapReady(GoogleMap googleMap)
private void updateMap(List<SubOrdinateLocation> locations) {
if (markers != null) {
markers.clear();
mGoogleMap.clear();
}
for (SubOrdinateLocation sol : locations) {
if (sol.latitude != 0.0 && sol.longitude != 0.0) {
LatLng sydney = new LatLng(sol.latitude, sol.longitude);
Marker marker = mGoogleMap.addMarker(new MarkerOptions().position(sydney).title(sol.subOrdinateId).snippet(sol.subOrdinateName));
markers.add(marker);
}
}
if (markers != null && markers.size() > 0) {
LatLngBounds.Builder builder = new LatLngBounds.Builder();
for (Marker marker : markers) {
builder.include(marker.getPosition());
}
LatLngBounds bounds = builder.build();
LatLng center = bounds.getCenter();
builder.include(new LatLng(center.latitude - 0.001f, center.longitude - 0.001f));
builder.include(new LatLng(center.latitude + 0.001f, center.longitude + 0.001f));
bounds = builder.build();
int padding = 0; // offset from edges of the map in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
mGoogleMap.animateCamera(cu);
}
}
Modify it as per your needs.
I can't resolve this problem. I trying to create Fragment with a map and I have this done. When I add static Long, Lat value the map show this o a map, But when I trying to make it automatic with getting localization in runnable the application just open the map and don't show specific LongLand values.
How to do this?
For getting long and late I'm using LocalizationManager, of course, I add permissions in manifest and also check runtime
public class LocalizationFragment extends Fragment implements OnMapReadyCallback {
private GoogleMap map;
MapView mapView;
View mview;
private double latitude, longtitude;
private Handler handler;
private Runnable runnable;
public LocalizationFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mview = inflater.inflate(R.layout.fragment_localization, container, false);
handler = new Handler();
getLocation();
if (ContextCompat.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 13);
}
if (ContextCompat.checkSelfPermission(getContext(), android.Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 11);
}
return mview;
}
#OnClick(R.id.button)
public void buttonStart() {
getLocation();
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mapView = (MapView) mview.findViewById(R.id.mapView);
if (mapView != null) {
mapView.onCreate(null);
mapView.onResume();
mapView.getMapAsync(this);
}
}
private void getLocation() {
LocationManager locationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
latitude = location.getLatitude();
longtitude = location.getLongitude();
}
};
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission
(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
#Override
public void onMapReady(final GoogleMap googleMap) {
MapsInitializer.initialize(getContext());
map = googleMap;
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
runnable = new Runnable() {
#Override
public void run() {
getLocation();
googleMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longtitude)).title("Statue").snippet("Something"));
CameraPosition liberty = CameraPosition.builder().target(new LatLng(latitude, longtitude)).zoom(15).bearing(0).tilt(45).build();
googleMap.moveCamera(CameraUpdateFactory.newCameraPosition(liberty));
handler.postDelayed(this, 5000);
}
};
}
}
You need to add markers form the main thread.add this to your runnable.
runOnUiThread(new Runnable() {
#Override
public void run() {
googleMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longtitude)).title("Statue").snippet("Something"));
}
});
I think this problem come from synchronize data. If you got location after add marker, it is meaningless, you get no location, and you have no marker on map, try to move action add marker into onLocationChanged
I'm trying to use the 'setInfoWindowAdapter' propery within my map view for a particular marker, but with 'Marker 2' there appears to be some unwanted space appearing underneath the title for some reason (Marker 2) (see attached screenshots). What can be done in order to prevent this from happening?
FragmentCustomMapview.java
public class FragmentCustomMapview extends android.support.v4.app.Fragment implements OnMapReadyCallback {
public FragmentCustomMapview() {
// Required empty constructor
}
GoogleMap mGoogleMap;
MapView mMapView;
SwitchCompat swt;
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_custommapview, container, false);
mMapView = (MapView) v.findViewById(R.id.map_custommapview);
mMapView.onCreate(savedInstanceState);
mMapView.getMapAsync(this); //this is important
swt = (SwitchCompat) v.findViewById(R.id.switch_map_custommapview);
return v;
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.getUiSettings().setZoomControlsEnabled(true);
mGoogleMap.setBuildingsEnabled(true);
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
swt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
initMap(isChecked);
}
});
initMap(swt.isChecked());
// Add markers and move the camera
LatLng marker1 = new LatLng(51.510256, -0.135106);
mGoogleMap.addMarker(new MarkerOptions()
.position(marker1)
.title("Lorem ipsum dolor")
.snippet("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
);
LatLng marker2 = new LatLng(51.509793, -0.134961);
mGoogleMap.addMarker(new MarkerOptions()
.position(marker2)
.title("Marker 2")
);
mGoogleMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker arg0) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
Context mContext = getActivity();
LinearLayout info = new LinearLayout(mContext);
info.setOrientation(LinearLayout.VERTICAL);
TextView title = new TextView(mContext);
title.setTextColor(Color.BLACK);
title.setGravity(Gravity.CENTER);
title.setTypeface(null, Typeface.BOLD);
title.setText(marker.getTitle());
title.setSingleLine(false);
TextView snippet = new TextView(mContext);
snippet.setTextColor(Color.GRAY);
snippet.setText(marker.getSnippet());
snippet.setMultiline(false)
info.addView(title);
info.addView(snippet);
return info;
}
});
// Updates the location and zoom level of the MapView
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(51.509932, -0.134720), 18);
mGoogleMap.animateCamera(cameraUpdate);
}
#Override
public void onResume() {
super.onResume();
mMapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mMapView.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
mMapView.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mMapView.onSaveInstanceState(outState);
}
#Override
public void onLowMemory() {
super.onLowMemory();
mMapView.onLowMemory();
}
private void initMap(boolean isChecked){
if (isChecked) {
mGoogleMap.setMapStyle(new MapStyleOptions(getResources().getString(R.string.style_json)));
} else {
mGoogleMap.setMapStyle(null);
}
}
}
1st marker
2nd marker
Don't add your TextView snippet to your LinearLayout info if your Marker has no snippet:
#Override
public View getInfoContents(Marker marker) {
Context mContext = getActivity();
LinearLayout info = new LinearLayout(mContext);
info.setOrientation(LinearLayout.VERTICAL);
TextView title = new TextView(mContext);
title.setTextColor(Color.BLACK);
title.setGravity(Gravity.CENTER);
title.setTypeface(null, Typeface.BOLD);
title.setText(marker.getTitle());
title.setSingleLine(false);
info.addView(title);
if (marker.getSnippet() != null) {
TextView snippet = new TextView(mContext);
snippet.setTextColor(Color.GRAY);
snippet.setText(marker.getSnippet());
snippet.setSingleLine(false);
info.addView(snippet);
}
return info;
}
How would I go through moving a marker on a Map Activity without having to long click and hold that marker until it receives focus?
I just want to touch and drag, but it takes around 1-2 secs before it receives focus and fires drag event.
here's my code:
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
Marker marker = mMap.addMarker(new MarkerOptions()
.position(latLng)
.draggable(true));
markers.add(marker);
updateUI();
}
});
mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() {
#Override
public void onMarkerDragStart(Marker marker) {
updateUI();
}
#Override
public void onMarkerDrag(Marker marker) {
updateUI();
}
#Override
public void onMarkerDragEnd(Marker marker) {
updateUI();
}
});
I am having issues with GoogleMap due to the fact that it gets the map asynchronously using MapView#getMapAsync.
I am experiencing a NullPointerException due to the #getMapAsync not returning in time when my Activity is passing markers to the GoogleMap object.
Can this be done synchronously or is there a better solution? Adding it to the fragment bundle would not work for me as the activity may pass the fragment markers after the #commit()
GoogleMapsFragment
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// inflate and return the layout
View v = inflater.inflate(R.layout.fragment_google_map, container,
false);
ButterKnife.bind(this, v);
mMapView.onCreate(savedInstanceState);
mMapView.onResume();// needed to get the map to display immediately
try {
MapsInitializer.initialize(getActivity().getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
Bundle bundle = getArguments();
if(bundle != null){
initialMarkers = bundle.getParcelableArrayList("markers");
}
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
if (mCameraPos != null) {
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(mCameraPos));
mCameraPos = null;
} else {
//Set default camera position over the United States.
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(37.09024, -95.712891)).zoom(3).build();
mGoogleMap.moveCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
}
}
});
return v;
}
Activity
#OnClick(R.id.loadListOrMapButton)
public void onClickChangeView() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (mLocationListViewFrag.isVisible()) {
if (mGoogleMapFrag == null) {
mGoogleMapFrag = new GoogleMapFragment();
fragmentTransaction.add(R.id.fragment_container, mGoogleMapFrag);
}
bListMapButton.setText(getString(R.string.list));
fragmentTransaction.hide(mLocationListViewFrag).show(mGoogleMapFrag);
} else {
bListMapButton.setText(getString(R.string.map));
fragmentTransaction.hide(mGoogleMapFrag).show(mLocationListViewFrag);
}
fragmentTransaction.commit();
fragmentManager.executePendingTransactions();
updateDisplay();
}
UpdateDisplay
public void updateDisplay() {
if (mLocationListViewFrag != null && mLocationListViewFrag.isVisible()) {
Log.d(TAG, "Update Tax Location ListView");
mLocationListViewFrag.setLocations(mLocations);
} else if (mGoogleMapFrag != null && mGoogleMapFrag.isVisible()) {
Log.d(TAG, "Update Google Maps Markers");
//Convert locations to markers to display.
mGoogleMapFrag.clearMarkers();
for (LocationObj aLocation : mLocations) {
mGoogleMapFrag.addMarker(new MarkerOptions().position(
new LatLng(Double.valueOf(aLocation.getLat()), Double.valueOf(aLocation.getLng()))).title(aLocation.getName()));
mGoogleMapFrag.fitBounds();
}
}
}
You should move the code that handles the markers to be within the OnMapReadyCallback (https://developers.google.com/android/reference/com/google/android/gms/maps/OnMapReadyCallback) that you pass to #getMapAsync(OnMapReadyCallback callback). This will ensure the markers aren't placed until the map is available.
EDIT for additional info
Ultimately you have to solve the problem of "what do I do if someone makes #onClickChangeView get called when the map isn't ready?" From a user experience perspective, the loadListOrMapButton shouldn't even be shown until the map finishes loading. You should disable the button by default, then make this button available from within your OnMapReadyCallback. You could either grey out the button (google for "android disable button" for examples) or you could actually hide/show it with View#setVisibility.
Non-recommended approach
Although I'm hesitant to suggest it, you could instead just check if the GoogleMap is ready: from within your OnMapReadyCallback set a boolean that your outside activity can check. Something like
private boolean mapIsReady = false;
mMapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
// your normal code here
mapIsReady = true;
}
});
public boolean mapIsReady() {
return mapIsReady;
}
Then in the activity
#OnClick(R.id.loadListOrMapButton)
public void onClickChangeView() {
// check for null and all that jazz
if (mapsFragment.mapIsReady()) {
// updateDisplay and everything
} else {
// make a toast or something asking them to try later.
}
}
xml
<com.google.android.gms.maps.MapView
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:apiKey="#string/google_app_id"
android:clickable="true">
</com.google.android.gms.maps.MapView>
MainActivity.java
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback {
LatLng sydney = new LatLng(33.8650, 151.2094);
MapView mapView;
GoogleMap map;
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapview);
mapView.getMapAsync(this);
MapsInitializer.initialize(this); /* initialize method should be called when we are not sure that map will be loaded before using it. It initialises the map.*/
mapView.onCreate(null);
mapView.onResume();
}
#Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
map.addMarker(new MarkerOptions().position(sydney).draggable(true));
}
}