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;
}
}
Related
I want to have a mapview like this suppose my main activity is like this
Here my main activity holds the instance of mapview in main activity and then when I click on it ,then a new activity should be opened with the map activity in android
You need to have the supportMapFragment in your xml file and get the reference of mapFragment into your MainFragment. The below code explains, How I accomplished the MapView inside Fragment. Write the below XML code in the mapView.xml and then Use the Fragment OnCreateView to get references.
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainMap"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="200dp"
/>
public class MapInFragment extends Fragment implements OnMapReadyCallback {
private View rootView;
private GoogleMap mMap;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.mapView, container, false);
try{
SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.mainMap);
mapFragment.getMapAsync(MapInFragment.this);
}catch (Exception e){
e.printStackTrace();
}
return rootView;
}
#Override
public void onMapReady(GoogleMap googleMap) {
try {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng croplatlng = new LatLng(Double.parseDouble(latitude), Double.parseDouble(longitude));
mMap.addMarker(new MarkerOptions().position(croplatlng).title(crop + "Field"));
//mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(croplatlng,16));
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(croplatlng , 16);
//mMap.addMarker(new MarkerOptions().position(location).title(""));
//mMap.moveCamera(CameraUpdateFactory.newLatLng(currentLocation ));
mMap.animateCamera(cameraUpdate,2000,null);
}catch (Exception e){
e.printStackTrace();
}
}
public void onDestroyView()
{
try {
Fragment fragment = (getChildFragmentManager().findFragmentById(R.id.mainMap));
if (fragment != null) {
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.remove(fragment);
ft.commit();
}
}catch (Exception e){
e.printStackTrace();
}
super.onDestroyView();
}
}
Step 1:
Add Mapview on your main activity.
Step 2:
Add OnClickListener on MapView
mMapView.getMap().setOnMapClickListener(new OnMapClickListener()
{
#Override
public void onMapClick(LatLng arg0)
{
//Open New Activity
}
});
Step 3:
Open New Activiy to show your map.
Hope you will find this answer usefull.
Happy Coading
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);
}
There is long time I'm trying to solve this issue. I've read so much questions about similiar issues on stackoverflow and other sources that I'm unable to list all of them.
My problem is different from the others I've read since the first time I try load the fragment with the map all works fine... Is on the second time I try to access the fragment with the map without restarting the app that it crashes with a null pointer on:
googleMap = map.getMap();
because map is null:
map = (SupportMapFragment) myContext.getSupportFragmentManager().
findFragmentById(R.id.map);
The key differences are then:
The first time it works fine
The second time findFragmentById returns null, but no error
I can't debug it because AVD emulator has no Google Play services installed.
MainActivity has a NavigationDrawer, and depending on the option selected, a Fragment or another is selected. Here some of the code related to this issue:
fragment_map.xml:
<?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.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
MyFragment.java:
...
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
...
public class MyFragment extends Fragment implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
private GoogleMap googleMap;
private View fragmentView;
private static WorldFragment fragment;
private FragmentActivity myContext;
...
public static MyFragment getInstance() {
if (fragment == null) {
fragment = new MyFragment();
}
return fragment;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
myContext = (FragmentActivity) activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
try {
GlobalState gs = (GlobalState) getActivity().getApplication();
// recover View from previous use
fragmentView = gs.getWorldFragmentView();
if (fragmentView == null) {
fragmentView = inflater.inflate(R.layout.fragment_map,
container, false);
// save View for next use
gs.setFragmentView(fragmentView);
} else {
ViewGroup parent = (ViewGroup) fragmentView.getParent();
parent.removeView(fragmentView);
}
} catch (InflateException e) {
// map is already there, just return view as it is
}
return fragmentView;
}
...
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Set up the map fragment
SupportMapFragment map = (SupportMapFragment) myContext.
getSupportFragmentManager().findFragmentById(R.id.map);
/* // If I active this code, no crash, but fragment remains
// in gray background without map.
// At least, if the app crashes, it restarts and the map
// gets loaded the first time
if (map == null) {
Toast.makeText(getActivity(), getString(R.string.maps_not_supported),
Toast.LENGTH_LONG).show();
return;
} */
googleMap = map.getMap();
if (googleMap != null) {
// Enable the current location "blue dot"
googleMap.setMyLocationEnabled(true);
...
} else {
Toast.makeText(getActivity(), getString(R.string.maps_not_supported),
Toast.LENGTH_LONG).show();
}
}
...
}
MainActivity.java:
public class MainActivity extends FragmentActivity implements
NavigationDrawerFragment.NavigationDrawerCallbacks {
#Override
public void onNavigationDrawerItemSelected(int position) {
Fragment contentFragment;
switch (selectedOption) {
case MAP:
contentFragment = MyFragment.getInstance();
break;
case XXX:
...
break;
default:
contentFragment = new OtherFragment();
}
// update the main content by replacing fragments
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, contentFragment)
.commit();
}
}
Stacktrace:
java.lang.NullPointerException
at xxx.xxxxx.xxx.fragments.MyFragment.onActivityCreated(MyFragment.java:193)
at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1508)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:958)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1115)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1478)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:446)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:153)
at android.app.ActivityThread.main(ActivityThread.java:5297)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:833)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at dalvik.system.NativeStart.main(NativeStart.java)
Please, let me know if you need some more information.
Thank you very much for your time and attention.
30/12/2014: source code of MainActivity's onCreate() method
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GlobalState applicationContext = (GlobalState) getApplicationContext();
applicationContext.updateLocale();
NavigationDrawerFragment.setItems(applicationContext.getMenuItems());
setContentView(R.layout.activity_main);
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
// Treating incoming notifications
Intent intent = getIntent();
String action = intent.getAction();
if (action != null && !action.isEmpty()) {
ItemType itemType = ItemType.valueOf(action);
String title = applicationContext.getMenuItemByType(itemType).getTitle();
String itemId = null;
try {
JSONObject json = new JSONObject(intent.getExtras().getString("com.parse.Data"));
itemId = json.getString(EXTRA_ITEM_ID);
} catch (JSONException e) {
Crashlytics.logException(e);
}
launchFragment(itemType, null, title, itemId);
}
}
You have to remove the fragment in the onDestroyView() method of your MyFragment class.
Sample code to remove:
#Override
public void onDestroyView() {
SupportMapFragment f = (SupportMapFragment)myContext.getSupportFragmentManager().findFragmentById(R.id.map);
if (f != null) {
try {
myContext.getSupportFragmentManager().beginTransaction().remove(f).commit();
}
catch (Exception e) {
e.printStackTrace();
}
}
super.onDestroyView();
}
My app selects one object of the listview and show the map. Works on first time running but in the second didn´t work. On third it works!
This is because of the inflate exception on the second time. It can´t return a view, or inflate it.
I need that every time it is selected something from the navigation drawer brings the map, im using replace and the method mentioned in many questions onDestroy, and obviusly removing the view when it is different from null.
Help would be appreciated!! Thanks!!
Code of the map:
public class mapfragmentplaces extends Fragment implements LocationListener {
protected LocationManager locationManager;
// GoogleMap googleMap;
LatLng myPosition;
private SupportMapFragment map;
private GoogleMap mMapView;
int fragVal2;
static Context ontext;
private static View view;
//lo que se ocupa para construir los sitios
String[] mPlaceType=null;
String[] mPlaceTypeName=null;
double mLatitude=0;
double mLongitude=0;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}
}
try {
view = inflater.inflate(R.layout.fragment_layout, container, false);
android.support.v4.app.FragmentManager fm = getFragmentManager();
/*
GoogleMapOptions gmo = (new GoogleMapOptions()).zoomControlsEnabled(false).rotateGesturesEnabled(false);
SupportMapFragment mapFragment = SupportMapFragment.newInstance(gmo);
android.support.v4.app.FragmentTransaction fragmentTransaction = getFragmentManager() .beginTransaction();
fragmentTransaction.add(R.id.mapFragmentHole, mapFragment);
fragmentTransaction.commit();
GoogleMap map = mapFragment.getMap(); */
map = (SupportMapFragment) fm.findFragmentById(R.id.map);
/* if (map == null) {
map = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.map, map).commit();
} */
// mMapView = fm.getMap();
mMapView = map.getMap();
// Enabling MyLocation Layer of Google Map
mMapView.setMyLocationEnabled(true);
// Getting LocationManager object from System Service LOCATION_SERVICE
LocationManager locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
// Creating a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Getting the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Getting Current Location From GPS
Location location = locationManager.getLastKnownLocation(provider);
if(location!=null){
onLocationChanged(location);
}
locationManager.requestLocationUpdates(provider, 20000, 0, this);
mMapView.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
Intent intent = new Intent(getActivity(), Stores.class);
startActivity(intent);
}
});
// Clears all the existing markers
mMapView.clear();
String Lugar = "Plaza fiesta";
String Desc = "Lugar bonito";
Double Lat3 = 25.751188242782035;
Double Lng3 = -100.3097140789032;
// notificacion(Results.toString());
mMapView.addMarker(new MarkerOptions()
.position(new LatLng(Lat3,Lng3))
.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker1))
.title(Lugar)
.snippet(Desc));
List<HashMap<String, String>> list = setPlaceTag.getList();
if (list!=null){
//((Menu) map).clear();
for(int i=0;i<list.size();i++){
// Creating a marker
MarkerOptions markerOptions = new MarkerOptions();
// Getting a place from the places list
HashMap<String, String> hmPlace = list.get(i);
// Getting latitude of the place
double lat = Double.parseDouble(hmPlace.get("lat"));
// Getting longitude of the place
double lng = Double.parseDouble(hmPlace.get("lng"));
// Getting name
String name = hmPlace.get("place_name");
// Getting vicinity
String vicinity = hmPlace.get("vicinity");
LatLng latLng = new LatLng(lat, lng);
// Setting the position for the marker
markerOptions.position(latLng);
// Setting the title for the marker.
//This will be displayed on taping the marker
markerOptions.title(name + " : " + vicinity);
// Placing a marker on the touched position
mMapView.addMarker(markerOptions);
}
}
} catch (InflateException e) {
/* map is already there, just return view as it is */
}
return view;
}
#Override
public void onLocationChanged(Location location) {
mLatitude = location.getLatitude();
mLongitude = location.getLongitude();
LatLng latLng = new LatLng(mLatitude, mLongitude);
mMapView.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMapView.animateCamera(CameraUpdateFactory.zoomTo(12));
}
#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 onDestroyView() {
super.onDestroyView();
Fragment fragment = (getFragmentManager().findFragmentById(R.id.map));
if (fragment != null)
getFragmentManager().beginTransaction().remove(fragment).commit();
}
}
In my main activity Im calling the mapfragmentplaces with this:
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//if (dataList.get(position).getTitle() == null) {
//SelectItem(position);
// } //Toast.makeText(getApplicationContext(), "diste click a sitios", Toast.LENGTH_SHORT).show();
//Currently selected item in spinner first is airport!!!
mTitle = setPlaceTag.getTag() ;
// Creating a fragment object
mapfragmentplaces rFragment = new mapfragmentplaces();
// Creating a Bundle object
Bundle data = new Bundle();
// Setting the index of the currently selected item of mDrawerList
data.putString("position", setPlaceTag.getTag());
// Setting the position to the fragment it is the value of the spinner
rFragment.setArguments(data);
// Getting reference to the FragmentManager
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
// Creating a fragment transaction
android.support.v4.app.FragmentTransaction ft = fragmentManager.beginTransaction();
// Adding a fragment to the fragment transaction
ft.replace(R.id.content_frame, rFragment);
// Committing the transaction
ft.commit();
// Closing the drawer
mDrawerLayout.closeDrawer(mDrawerList);
}
}
My xml for maps:
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment" />
Check your onCreateView method. I dont think its the correct way to inflate a xml file in oncreateview method. Please try this:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout.,container,false);
//start inflating the view and return the view
map = (SupportMapFragment) getFragmentManager().findFragmentById(R.id.map);
}
A good place to utilize and use view methods is onStart of the fragment.
#Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
mMapView = map.getMap();
}
Also I see that you are mixing the support package from the fragment. See this line:
android.support.v4.app.FragmentManager fm = getFragmentManager();
Make sure that all your import's and code for fragment are either from support package or from default package(api 11 or greater). This is a common source of bugs like classcastexception.
I have a fragment which is a part of Viewpager, and I want to use Google Map V2 inside that fragment. This is what I have tried so far,
In my fragment,
private SupportMapFragment map;
private GoogleMap mMapView;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getChildFragmentManager();
map = (SupportMapFragment) fm.findFragmentById(R.id.map);
if (map == null) {
map = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.map, map).commit();
}
}
#Override
public void onResume() {
super.onResume();
if (mMapView == null) {
mMapView = map.getMap();
Marker hamburg = mMapView.addMarker(new MarkerOptions().position(HAMBURG)
.title("Hamburg"));
Marker kiel = mMapView.addMarker(new MarkerOptions()
.position(KIEL)
.title("Kiel")
.snippet("Kiel is cool")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.ic_launcher)));
mMapView.moveCamera(CameraUpdateFactory.newLatLngZoom(HAMBURG, 15));
// Zoom in, animating the camera.
mMapView.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
}
}
and in my layout subfragment_info.xml , I have,
<fragment
android:id="#+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_alignParentLeft="true"
android:layout_below="#+id/tableLayout1" />
I can see the map now. But the markers are not showing. I think my Google map mMapView is null. Please help me to get this problem solved. Thanks in advance.
Create a frame for map in which it will be added in your xml layout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/map_container">
<!-- The map fragments will go here -->
</RelativeLayout>
Don't include class="com.google.android.gms.maps.SupportMapFragment" in xml
either in your fragment class do get it manually inside onActivityCreated
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FragmentManager fm = getChildFragmentManager();
fragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
if (fragment == null) {
fragment = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.map_container, fragment).commit();
}
/***at this time google play services are not initialize so get map and add what ever you want to it in onResume() or onStart() **/
}
#Override
public void onResume() {
super.onResume();
if (map == null) {
map = fragment.getMap();
map.addMarker(new MarkerOptions().position(new LatLng(0, 0)));
}
}
if you guys face any problem Illegal State Exception Occur just write below code
/*
* This issue Is tracked in (Google Bugs)
* http://code.google.com/p/gmaps-api-issues/issues/detail?id=5064 Added
* Code Due to Illegal State Exception Occur when reclicking on tab
*
* A short-term workaround that fixed it for me is to add the following to
* onDetach() of every Fragment which you call
*/
#Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class
.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
//If you want to show map in activity just extend your Activity by //FragmentActivity write code mention below
In onCreate
FragmentManager fm = getSupportFragmentManager();
fragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
if (fragment == null) {
fragment = SupportMapFragment.newInstance();
fm.beginTransaction().replace(R.id.map_container, fragment)
.commit();
}
In onResume
#Override
protected void onResume() {
super.onResume();
if (googleMap == null) {
initilizeMap();
}
}
private void initilizeMap() {
if (googleMap != null) {
googleMap = fragment.getMap();
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
googleMap.getUiSettings().setMyLocationButtonEnabled(true);
googleMap.getUiSettings().setCompassEnabled(true);
googleMap.getUiSettings().setRotateGesturesEnabled(true);
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(latitude, longitude)).zoom(10).build();
googleMap.animateCamera(CameraUpdateFactory
.newCameraPosition(cameraPosition));
// create marker
MarkerOptions marker = new MarkerOptions().position(new LatLng(
latitude, longitude));
// ROSE color icon
marker.icon(BitmapDescriptorFactory
.defaultMarker(BitmapDescriptorFactory.HUE_ROSE));
// adding marker
googleMap.addMarker(marker);
// check if map is created successfully or not
if (googleMap == null) {
Toast.makeText(getApplicationContext(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
}
}
}
Additional help can get from these links
https://code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1
https://developers.google.com/maps/documentation/android/map
You have to decide if you create your fragment in code new SupportMapFragment() or inflate from xml class="com.google.android.gms.maps.SupportMapFragment".
Actually you cannot have a Fragment in xml for another Fragment. Read about nested Fragments.
You may follow this comment on how to add nested SupportMapFragment.
I had more or less the same problem. I had a Navigation Drawer and I wanted to put the map in a fragment.
I followed this thread (but it is in Spanish):
https://groups.google.com/forum/#!msg/desarrolladores-android/1cvqPm0EZZU/Q801Yvb2ntYJ
The clue was (in my opinion) to change the layout.xml file:
Instead of a "fragment" inside your "layout subfragment_info.xml" you would need to change to this:
<com.google.android.gms.maps.MapView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />`
Here it is the code inside the thread (you could use it and adapt):
https://groups.google.com/d/msg/desarrolladores-android/1cvqPm0EZZU/9srw_9feamUJ
my approach is:
Bundle bundle = new Bundle();
bundle.putInt(MY_ID, id);
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.customer_details_fragment);
fragment = new SalesFragment();
fm.beginTransaction()
.add(R.id.customer_details_fragment, fragment)
.commit();
fragment.setArguments(bundle);
For MapFragment
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
In your Fragment Class
map = ((MapFragment) getActivity().getFragmentManager()
.findFragmentById(R.id.map)).getMap();
map.addMarker(new MarkerOptions().position(
new LatLng(13.031902, 80.278823)).title("Marker Title"));
For SupportMapFragment
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
In your Fragment Class
map = ((SupportMapFragment) getActivity().getSupportFragmentManager()
.findFragmentById(R.id.map)).getMap();
map.addMarker(new MarkerOptions().position(
new LatLng(13.031902, 80.278823)).title("Marker Title"));
Note - SupportMapFragment map render once user touchs the map
In link , answer for you:
"The problem is that what you are trying to do shouldn't be done. You shouldn't be inflating fragments inside other fragments. From Android's documentation:
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.
While you may be able to accomplish the task with the hacks presented here, I highly suggest you don't do it. Its impossible to be sure that these hacks will handle what each new Android OS does when you try to inflate a layout for a fragment containing another fragment.
The only Android-supported way to add a fragment to another fragment is via a transaction from the child fragment manager."
For this problem:
Duplicate ID, tag null, or parent id with another fragment for com.google.android.gms.maps.MapFragment
For me, the best solution are of #DeepakPanwar
For Load map into fragment:
<fragment
android:id="#+id/fragmentMap1"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
For .java:
public class PathFragment extends Fragment {
View view;
GoogleMap mMap;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view=inflater.inflate(R.layout.fragment_path,null);
setupMap();
return view;
}
private void setupMap()
{
if (mMap == null)
{
mMap = ((SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.fragment_map1)).getMap();
mMap.getUiSettings().setZoomControlsEnabled(true);
}
mMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
#Override
public void onMapLoaded() {
getlocation();
}
});
}
public void getlocation()
{
try
{
/*Collect Source and destination latitude and longitude
* To draw Polyline
* */
LatLng src = new LatLng(Double.parseDouble(AppGlobal.WorkerHistory.getOrder_lat()),Double.parseDouble(AppGlobal.WorkerHistory.getOrder_lng()));
LatLng dest =new LatLng(Double.parseDouble(AppGlobal.WorkerHistory.getWorker_lat()),Double.parseDouble(AppGlobal.WorkerHistory.getWorker_lng()));
//Add Marker
mMap.addMarker(new MarkerOptions()
.position(src)
.title("Source")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.srcicon)));
mMap.addMarker(new MarkerOptions()
.position(dest)
.title("Destination")
.icon(BitmapDescriptorFactory.fromResource(R.drawable.desticon)));
Polyline line = mMap.addPolyline(
new PolylineOptions().add(
new LatLng(src.latitude, src.longitude),
new LatLng(dest.latitude, dest.longitude)
).width(5).color(Color.RED).geodesic(true)
);
//set zoom level
LatLngBounds.Builder builder = new LatLngBounds.Builder();
builder.include(src);
builder.include(dest);
LatLngBounds bounds = builder.build();
int padding = 0; // offset from edges of the map in pixels
CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
mMap.animateCamera(cu);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
This is how I did it
in layout:
<fragment
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight=".90"
class="com.google.android.gms.maps.SupportMapFragment"
/>
in code:
public class GPS extends FragmentActivity {
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (supportMap == null) {
// Try to obtain the map from the SupportMapFragment.
supportMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (supportMap != null) {
MarkerOptions mo = new MarkerOptions().position( new LatLng( latitude, longitude ) );
supportMap.addMarker( mo );
}
}
}
}
Took me a lot of fiddling, you need just the right combination of things, make sure your class extends FragmentActivity
If I replace the fragment, where the map fragment is in (in this code example MyFragment) with a different fragment and then come back, I get an IllegalStateException
public class Home_Map extends Fragment {
GoogleMap googleMap;
FragmentManager myFragmentManager;
SupportMapFragment mySupportMapFragment;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View rootView = inflater.inflate(R.layout.fragment_home__map, container, false);
//googleMap.setMyLocationEnabled(true);
try {
// Loading map
initilizeMap();
googleMap.setMyLocationEnabled(true);
} catch (Exception e) {
e.printStackTrace();
}
return rootView;
}
private void initilizeMap() {
try
{
if (googleMap == null) {
myFragmentManager = getFragmentManager();
mySupportMapFragment = (SupportMapFragment)myFragmentManager.findFragmentById(R.id.map2);
googleMap = mySupportMapFragment.getMap();
if (googleMap == null) {
Toast.makeText(getActivity().getApplicationContext(),
"Sorry! unable to create maps", Toast.LENGTH_SHORT)
.show();
}
}
} catch (Exception e) { Toast.makeText(getActivity().getApplicationContext(), ""+e, 1).show();
// TODO: handle exception
}
}
#Override
public void onResume() {
super.onResume();
initilizeMap();
}
#Override
public void onDetach() {
// TODO Auto-generated method stub
super.onDetach();
try {
Field childFragmentManager = Fragment.class
.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}