A long time i used this code, to 'reuse' a GoogleMap in Fragment - when switching to another Fragment and opening the MapFragment again, the Map and all its content was as before (no zooming-in again, no need to re-set Markers, it was 'just in background' and brought to front again):
public class MapFragmentGoogle extends Fragment implements SensorEventListener, OnMapLoadedCallback {
private static View rootView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (rootView != null) {
ViewGroup parent = (ViewGroup) rootView.getParent();
if (parent != null)
parent.removeView(rootView);
}
try {
rootView = inflater.inflate(R.layout.fragment_map_google, container, false);
} catch (InflateException e) {
//
}
return rootView;
So now i switched from eclipse to AndroidStudio (i kow i'm late), which is implementing the latest PlayServices and i cannot use
map = ((SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.gmap)).getMap();
anymore and the 'Reuse-Code" does not work anymore. I'am getting tiered about those things.
How can i have a GoogleMap, which stays exactly as it is, no new init, no zomming from space to place, not redrawing Polylines and Markersetc etc when switching to another fragment and then back to the mapfragment?
You can still use supportmapfragment, please find the code below:
XML:
<fragment
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:name="com.google.android.gms.location.places.ui.PlaceAutocompleteFragment"
android:id="#+id/search1"
>
code:
SupportMapFragment mapFragment;
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.maps);
mapFragment.getMapAsync(this);
ldb = new LocationDatabase(this);
intentlat = null;
intentlng = null;
public void onMapReady(GoogleMap googleMap) {
m_map = googleMap;
map_false = true;
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
m_map.setMyLocationEnabled(true);
m_map.getUiSettings().setMapToolbarEnabled(true);
m_map.getUiSettings().setZoomControlsEnabled(true);
m_map.getUiSettings().setZoomGesturesEnabled(true);
m_map.getUiSettings().setMyLocationButtonEnabled(true);
geocoder = new Geocoder(this, Locale.getDefault());
addresses = null;
if (intentlat == null && intentlng == null) {
LatLng target3 = new LatLng(<latitude>, <81.488100>);
CameraPosition nnn = CameraPosition.builder().target(target3).zoom(14).build();
m_map.animateCamera(CameraUpdateFactory.newCameraPosition(nnn), 2000, null);
CameraPosition nnn = CameraPosition.builder().target(target3).zoom(14.0f).build();
m_map.animateCamera(CameraUpdateFactory.newCameraPosition(nnn), 2000, null);
}
Related
I want to show mylocationbutton in my app. For that, I added setMyLocationEnabled(true) in my code. But it's not working. Please suggest me a solution for this. Here is my code.
My minimum and maximum sdk are 16 and 26 respectively
here is my mapFragment where I wrote my code to set myLocation button
MapFragment.java
public class MapFragment extends Fragment implements OnMapReadyCallback {
private static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1;
private GoogleMap mMap;
private boolean isUp;
private View addressView,mapView;
private View searchLayout;
private TextView addressLine1, addressLine2;
private Button cancel, select;
private Geocoder geocoder;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
//ToDo : Replace with orginal view
View view = inflater.inflate(R.layout.fragment_map, null, false);
init(view);
SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
mapView = mapFragment.getView();
setListeners();
return view;
}
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
mMap.getUiSettings().setMyLocationButtonEnabled(true);
mMap.setMyLocationEnabled(true);
isUp = false;
addressView.setVisibility(View.INVISIBLE);
// Add a marker in Sydney and move the camera
mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
#Override
public void onMapClick(LatLng latLng) {
setUpMarker(latLng);
geocoder = new Geocoder(getContext());
try {
List<Address> addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1);
search(addresses);
} catch (IOException e) {
e.printStackTrace();
}
}
});
if (mapView != null &&
mapView.findViewById(Integer.parseInt("1")) != null) {
// Get the button view
View locationButton = ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));
// and next place it, on bottom right (as Google Maps app)
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
locationButton.getLayoutParams();
// position on right bottom
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
layoutParams.setMargins(0, 0, 30, 30);
}
}
}
My xml file
fragment_map.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.HomeActivity" />
Permissions in manifest file
Manifest file
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
I try display Google Maps inside my Fragment. The problem is when I run my project I do not see this maps. The additional information is this fragments belongs to Pager View.
This is my sample of code:
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
thisContext = inflater.getContext();
View view = inflater.inflate(R.layout.tab_fragment_2, container, false);
loadMap();
// initializeMap();
locationManager = (LocationManager) thisContext.getSystemService(Context.LOCATION_SERVICE);
if (ActivityCompat.checkSelfPermission(thisContext, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(thisContext, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return null;
}
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, this);
return view;
}
private void initializeMap() {
if (map == null) {
SupportMapFragment mapFrag = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
mapFrag.getMapAsync(this);
}
}
private void loadMap() {
SupportMapFragment mSupportMapFragment;
mSupportMapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
if (mSupportMapFragment == null) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
mSupportMapFragment = SupportMapFragment.newInstance();
fragmentTransaction.replace(R.id.map, mSupportMapFragment).commit();
}
if (mSupportMapFragment != null) {
mSupportMapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap googleMap) {
if (googleMap != null) {
googleMap.getUiSettings().setAllGesturesEnabled(true);
// -> marker_latlng // MAKE THIS WHATEVER YOU WANT
//CameraPosition cameraPosition = new CameraPosition.Builder().target(marker_latlng).zoom(15.0f).build();
// CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition);
// googleMap.moveCamera(cameraUpdate);
}
}
});
}
}
The problem is when I run my project I do not see this maps.
You can use the default 'new Activity' wizard to create Google maps activity.
It includes all the information you need. See the 7th item in the following screenshot.
The best thing so far I know for Fragment is to use MapView instead of MapFragment. I am using MapView inside a Navigation Drawer Fragment and its working fine with all callbacks that I need and PlacesAutoComplete.
I have been working in Navigation Drawer Activity, it has many fragments and one of the fragment contains MapFragment.
Now there is a problem in MapFragment i-e When for the first time i open the fragment that contains MapFragment inside it everything works fine, but once i navigate to some other fragment using getFragmentManager().beginTransaction().replace(...)
and then return to previous fragment using getFragmentManager().popBackStack();
My mapFragment.getView() does not works, you can review my code for MapFragment
private void initMap() {
if (mapFragment == null)
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.mapView);
if (mapFragment == null)
mapFragment = (MapFragment) this.getChildFragmentManager().findFragmentById(R.id.mapView);
if (mapFragment == null) {
Toast.makeText(getActivity(), "mapFragment not initialized", Toast.LENGTH_SHORT).show();
}
if (mapFragment.getView() == null) {
Toast.makeText(getActivity(), "getView not initialized", Toast.LENGTH_SHORT).show();
}
mapFragment.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap mMap) {
googleMap = mMap;
Toast.makeText(getActivity(), "map intialized", Toast.LENGTH_SHORT).show();
// For showing a "move to my location" button
CheckPermissions cp = new CheckPermissions(getActivity());
if (cp.getPermission(Manifest.permission.ACCESS_COARSE_LOCATION) || cp.getPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
// enableMyLocation();
} else {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION);
}
mUiSettings = mMap.getUiSettings();
mUiSettings.setZoomControlsEnabled(true);
mUiSettings.setCompassEnabled(true);
cameraListener();
markerListener();
mapListener();
}
});
}
above method is called if following method
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initMap();
if (mapFragment.getView() != null) {
mapFragment.getView().setVisibility(View.GONE);
}
}
i have searched a lot on every platform but not getting any help.
and i do not want to use SupportFragmentManager because i'm not creating this app for older android versions.
Any help would be appreciable.
Regards.
UPDATE
I have sorted my problem temporarily by putting MapFragment inside RelativeLayout and hiding this RelativeLayout
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initMap();
relativeLayout = (RelativeLayout) view.findViewById(R.id.rel_layout);
if (relativeLayout != null) {
relativeLayout.setVisibility(View.GONE);
}
}
I think your first line of code is what makes your fragment disappear.
Delete this:
if (mapFragment == null)
mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.mapView);
Whenever you are adding a fragment as child to existing fragment, you want to use getChildFragmentManager().
EDIT:
To show / hide / remove child fragment, you can use one of the following methods:
getChildFragmentManager().beginTransaction().hide(fragment).commit();
getChildFragmentManager().beginTransaction() has various methods for managing fragments, such as show / remove / replace / add, etc.
You can try these, though I'm not sure why you wish to hide MapFragment immediately after creating it.
I can access map when I call the fragment first time but when I call the fragment second time it gives me this caused by error:
12-26 09:36:41.306: E/AndroidRuntime(28156): Caused by: java.lang.IllegalArgumentException: Binary XML file line #164: Duplicate id 0x7f090012, tag null, or parent id 0x0 with another fragment for com.google.android.gms.maps.SupportMapFragment
I create the inner map fragment in my fragment class' onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Defines the xml file for the fragment
View view = inflater.inflate(R.layout.howtogo_fragment, container,
false);
if(map==null)
map = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.map))
.getMap();
}
here is the layout of my fragment:
<LinearLayout>
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
</LinearLayout>
Try this .
private static GoogleMap mMap;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
view = (RelativeLayout) inflater.inflate(R.layout.howtogo_fragment, container, false);
MapLoad(); // For setting up the MapFragment
return view;
}
/***** Sets up the map if it is possible to do so *****/
public static void MapLoad() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) YOURACTIVITY.fragmentManager
.findFragmentById(R.id.map)).getMap();
// Check if we were successful in obtaining the map.
if (mMap != null)
setUpMap();
}
}
private static void setUpMap() {
// For showing a move to my loction button
mMap.setMyLocationEnabled(true);
// For dropping a marker at a point on the Map
// mMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title("My Home").snippet("Home Address"));
// For zooming automatically to the Dropped PIN Location
// mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude,
// longitude), 12.0f));
}
You can try my code:
xml code:
<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"
android:background="#android:color/white"
tools:context="com.example.catalyst_home.GeolocationActivity$PlaceholderFragment" >
<RelativeLayout
android:id="#+id/map_root"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</RelativeLayout>
Fragment java:
private GoogleMap mMap;
private SupportMapFragment mMapFragment;
private void setUpMapIfNeeded() {
if (mMap == null) {
mMapFragment = SupportMapFragment.newInstance();
FragmentTransaction fragmentTransaction = getChildFragmentManager()
.beginTransaction();
fragmentTransaction.add(R.id.map_root, mMapFragment);
fragmentTransaction.commit();
}
}
in onResum of fragment:
#Override
public void onResume() {
super.onResume();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
mMap = mMapFragment.getMap();
if (mMap != null) {
mMap.setMyLocationEnabled(true);
}
}
}, 2000);
}
I am working on a app that has 4 tabs, and 1 tab is google map.
When the user click on it , it can create the map correctly, however, if the user leave the current tab by click on other tab, and come back to this tab again, it will throw exception of error inflating layout XML.
So I log the flow, I found that in the onCreateView the second time , rootview is already create, but when I add if (rootView == null) , it still throw error of "need to removeView on child view" . How to fix that? Thanks.
public class Map extends Fragment {
// Google Map
private GoogleMap googleMap;
private boolean isShowRoute;
private Database db;
private ArrayList<Restaurant> rList;
private ArrayList<Spot> sList;
View rootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("test1","" + rootView);
rootView = inflater.inflate(R.layout.map, container, false);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
Log.d("test1","b");
super.onActivityCreated(savedInstanceState);
db = new Database (getActivity());
rList = db.getRestaurant();
sList = db.getSpot();
try {
initilizeMap();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* function to load map. If map is not created it will create it for you
* */
private void initilizeMap() {
if (googleMap == null) {
googleMap = ((MapFragment) getActivity().getFragmentManager().findFragmentById(R.id.map)).getMap();
// check if map is created successfully or not
if (googleMap == null) {
Toast.makeText(getActivity().getApplicationContext(),"Sorry! unable to create maps", Toast.LENGTH_SHORT).show();
} else {
googleMap.setMyLocationEnabled(true);
googleMap.getUiSettings().setCompassEnabled(true);
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
if (isShowRoute)
showRoute();
else
pinMap();
}
}
}
private void showRoute() {
// if (RunTracker.routePoints.size() > 1){
// Polyline route = googleMap.addPolyline(new PolylineOptions()
// .geodesic(true));
// route.setPoints(RunTracker.routePoints);
//
// LatLng lastLatLng = RunTracker.routePoints.get(RunTracker.routePoints.size() - 1);
// googleMap.addMarker(new MarkerOptions().position(lastLatLng).title("You are here"));
// googleMap.moveCamera( CameraUpdateFactory.newLatLngZoom(lastLatLng, 16.0f) );
// }
}
private void pinMap() {
for (Restaurant r : rList) {
MarkerOptions marker = new MarkerOptions().position(new LatLng(r.lat, r.lng)).title(r.name);
marker.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
googleMap.addMarker(marker);
}
for (Spot s : sList) {
MarkerOptions marker = new MarkerOptions().position(new LatLng(s.lat, s.lng)).title(s.name);
marker.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
googleMap.addMarker(marker);
}
googleMap.moveCamera( CameraUpdateFactory.newLatLngZoom(new LatLng(22.3079136,114.1778376), 10.0f) ); // go to MK MTR station by default
}
#Override
public void onResume() {
super.onResume();
initilizeMap();
}
}
Log cat
03-31 14:53:56.669: E/AndroidRuntime(4611): android.view.InflateException: Binary XML file line #6: Error inflating class fragment
Caused by: java.lang.IllegalArgumentException: Binary XML file line #6: Duplicate id 0x7f050006, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.MapFragment
Layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Update Code:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
db = new Database (getActivity());
if (rList == null && sList == null) {
rList = db.getRestaurant();
sList = db.getSpot();
}
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.map, container, false);
try {
initilizeMap();
} catch (Exception e) {
e.printStackTrace();
}
return rootView;
}
#Override
public void onDestroyView() {
super.onDestroyView();
if (mMap != null) {
getActivity().getSupportFragmentManager().beginTransaction().remove(getActivity().getSupportFragmentManager().findFragmentById(R.id.map)).commit();
mMap = null;
}
}
The mapfragment's id must be removed from the FragmentManager
or else if the same it is passed on the next time then
app will crash
You can't add fragment inside a fragment. From Android document
Note: You cannot inflate a layout into a fragment when that layout includes a . Nested fragments are only supported when added to a fragment dynamically.
You get MapFragment from activity but after you change tab your fragment's life cycle changed, not activity. When you select tab 1 (MapFragment), it will try to get MapFragment again.
So you should try
googleMap = ((MapFragment) getChildFragmentManager().findFragmentById(R.id.map)).getMap();
or you should remove MapFragment from fragment manager of activity.
Link
user782104 is correct that solved my same problem! I'm my case i was using a fragment so its:
#Override
public void onDestroyView() {
super.onDestroyView();
if(mMap != null)
{
getFragmentManager().beginTransaction().remove(getFragmentManager().findFragmentById(R.id.mapFrag)).commit();
mMap = null;
}
}