Reputation: 1739
I am developing an app using a NavigationDrawer
i.e. DrawerLayout
and navigating to different Fragments
. When I call a Map_Fragment_Page
the application crashes, but not the first time. For the first time it displays the Map
properly but after that when I navigate different fragments and again come to Map_Fragment_Page
then it crashes giving an error android.view.InflateException: Binary XML file line #8: Error inflating class fragment
I tried so many different solutions and I also also searched on Google
but still not getting the required solution. The problem is not yet fixed.
howtoreach.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/howtoreach_map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.SupportMapFragment"/>
</RelativeLayout>
HowToReach.java
package com.demo.map.howtoreach;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import android.support.v4.app.Fragment;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
import com.demo.map.R;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Color;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
public class HowToReach extends Fragment
{
public static final String TAG = "fragment_5";
ProgressDialog dialog;
GoogleMap googleMap;
Marker marker;
LocationManager locationManager;
Location location;
Criteria criteria;
String provider;
double latitude, longitude;
public HowToReach(){}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.howtoreach, container, false);
dialog = ProgressDialog.show(getActivity(),"","Loading",true,false);
int secondsDelayed = 4;
new Handler().postDelayed(new Runnable()
{
public void run()
{
dialog.dismiss();
}
}, secondsDelayed * 1000);
try
{
// Loading map
if (googleMap == null)
{
googleMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.howtoreach_map)).getMap();
googleMap.setMyLocationEnabled(true);
locationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
criteria = new Criteria();
provider = locationManager.getBestProvider(criteria, true);
location = locationManager.getLastKnownLocation(provider);
latitude = location.getLatitude();
longitude = location.getLongitude();
// create marker
marker = googleMap.addMarker(new MarkerOptions().position(
new LatLng(latitude, longitude)).title("You are Here"));
marker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
marker.showInfoWindow();
CameraPosition cameraPosition = new CameraPosition.Builder().target(
new LatLng(latitude, longitude)).zoom(15).build();
googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
Polyline line = googleMap.addPolyline(new PolylineOptions()
.add(new LatLng(latitude, longitude), new LatLng(18.520897,73.772396))
.width(2).color(Color.RED).geodesic(true));
marker = googleMap.addMarker(new MarkerOptions().position(
new LatLng(18.520897, 73.772396)).title("DSK Ranwara Road"));
marker.setIcon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED));
// check if map is created successfully or not
if (googleMap == null)
{
Toast.makeText(getActivity(),"Sorry! unable to create maps", Toast.LENGTH_SHORT).show();
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return v;
}
}
Upvotes: 47
Views: 94234
Reputation: 3385
How i fixed my issue after searching alot, Put these lines inside fragment onPause Method.
@Override
public void onPause() {
super.onPause();
final FragmentManager fragManager = this.getChildFragmentManager();
final Fragment fragment = fragManager.findFragmentById(R.id.map);
if(fragment!=null){
fragManager.beginTransaction().remove(fragment).commit();
googleMap=null;
}
}
It is compulsory to null googlemap. There is no need to use MapView, you can do it without using MapView
Upvotes: 0
Reputation: 1772
I got the same error message:
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState){
super.onCreateView(inflater,container,savedInstanceState);
self_view=inflater.inflate(R.layout.fragment_player,container,false);
return self_view;
}
onCreateView
may be called more than once.When that happens, the above code creates a new view for the fragment while the old one is still around.
The error pops up with some adapter and does not with another; in my case FragmentStatePagerAdapter was happy and FragmentPagerAdapter was murderous because the former destroyed its fragments and the latter reused them.
Upvotes: 0
Reputation: 1766
My experiences made with fragments added by xml-tag
<fragment>...</fragment>.
Those fragments are normally nested and do not destroy when the parent fragment gets destroyed. Once you try to inflate them again, you get the exception which basically complains of having this fragment already inflated. Therefore I destroy my nested fragments manually once the parent fragment gets destroyed. Simply use the following snipped and adjust it to your needs. This code resides in the parent fragment which has the nested fragment as xml-tag.
@Override
public void onDestroy() {
super.onDestroy();
final FragmentManager fragManager = this.getFragmentManager();
final Fragment fragment = fragManager.findFragmentById(/*id of fragment*/);
if(fragment!=null){
fragManager.beginTransaction().remove(fragment).commit();
}
}
With dynamically created fragments there are no problems at all. Dynamically means: You have no fragment-xml-tag used
Hope this helps! Good programming!
Upvotes: 8
Reputation: 133560
Yes.. I want Map inside a Fragment.
You should use a MapView
http://developer.android.com/reference/com/google/android/gms/maps/MapView.html
public class HowToReach extends Fragment {
MapView mapView;
GoogleMap map;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment2, container, false);
// Gets the MapView from the XML layout and creates it
try {
MapsInitializer.initialize(getActivity());
} catch (GooglePlayServicesNotAvailableException e) {
Log.e("Address Map", "Could not initialize google play", e);
}
switch (GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()) )
{
case ConnectionResult.SUCCESS:
Toast.makeText(getActivity(), "SUCCESS", Toast.LENGTH_SHORT).show();
mapView = (MapView) v.findViewById(R.id.map);
mapView.onCreate(savedInstanceState);
// Gets to GoogleMap from the MapView and does initialization stuff
if(mapView!=null)
{
map = mapView.getMap();
map.getUiSettings().setMyLocationButtonEnabled(false);
map.setMyLocationEnabled(true);
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(new LatLng(43.1, -87.9), 10);
map.animateCamera(cameraUpdate);
}
break;
case ConnectionResult.SERVICE_MISSING:
Toast.makeText(getActivity(), "SERVICE MISSING", Toast.LENGTH_SHORT).show();
break;
case ConnectionResult.SERVICE_VERSION_UPDATE_REQUIRED:
Toast.makeText(getActivity(), "UPDATE REQUIRED", Toast.LENGTH_SHORT).show();
break;
default: Toast.makeText(getActivity(), GooglePlayServicesUtil.isGooglePlayServicesAvailable(getActivity()), Toast.LENGTH_SHORT).show();
}
// Updates the location and zoom of the MapView
return v;
}
@Override
public void onResume() {
mapView.onResume();
super.onResume();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}
fragment2.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">
<com.google.android.gms.maps.MapView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/map" />
</RelativeLayout>
Update:
https://developers.google.com/android/reference/com/google/android/gms/maps/MapView#public-constructors
getMap()
is deprecated. Use getMapAsync(OnMapReadyCallback)
instead. The callback method provides you with a GoogleMap instance guaranteed to be non-null and ready to be used.
Upvotes: 63
Reputation: 482
In Your Class
View mTrackView = inflater.inflate(R.layout.mylayout, container, false);
SupportMapFragment mSupportMapFragment = SupportMapFragment.newInstance();
FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.mapwhere, mSupportMapFragment);
fragmentTransaction.commit();
if(mSupportMapFragment!=null){
googleMap = mSupportMapFragment.getMap();
if(googleMap!=null){
googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
googleMap.getUiSettings().setMyLocationButtonEnabled(false);
googleMap.setMyLocationEnabled(false);
if (mgpr_tracker.canGetLocation())
CURREN_POSITION = new LatLng(mgpr_tracker.getLatitude(),
mgpr_tracker.getLongitude());
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(
CURREN_POSITION, ZOOM_LEVEL);
googleMap.animateCamera(cameraUpdate);
}
}
mylayout.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.03"
android:id="@+id/mapwhere" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Upvotes: 1
Reputation: 827
I put this in my fragment
@Override
public void onPause() {
super.onPause();
getChildFragmentManager().beginTransaction()
.remove(mMapFragment)
.commit();
}
It working without replacing to the MapView.
Upvotes: 4
Reputation: 3995
For Google API v2 to work (I am also using SupportMapFragment), you must include these permissions
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:glEsVersion="0x00020000" android:required="true"/>
I hope this will help you guys.
P.S I used these permissions for adding a simple map in my app. There are certain other permissions which this link suggests as well.
Upvotes: 0
Reputation: 10767
I put this in my fragment when I have a viewpager:
@Override
public void onPause() {
Fragment fragment = (getChildFragmentManager().findFragmentById(R.id.fragment_map_map));
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.remove(fragment);
ft.commit();
super.onPause();
}
Upvotes: 0
Reputation: 10633
Check out that whether you have the exact manifest permission. I had not included the below permission in manifest, and it were giving this error.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Please include some of the following permission in your manifest file
<!-- - THIS IS THE USER PERMISSION FOR GETTING LATITUDE AND LONGTITUDE FROM INTERNET -->
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
Upvotes: 0
Reputation: 1248
So if it crashes after opening the fragment second time. All you need is this in OnDestroy
@Override
public void onDestroy() {
super.onDestroy();
getFragmentManager().beginTransaction().remove(mapfragmentnamehere).commit();
}
Make what changes you need if you're using support fragment
Upvotes: 10
Reputation:
As you are telling first time your code is working so i think when you again call your map your googlemap
object is not null
and you have not handled it properly try to Implement like this in your code
if (googleMap == null) {
// Your code
} else if(googleMap != null) {
marker = googleMap.addMarker(new MarkerOptions().position(new LatLng(18.520897, 73.772396)).title("DSK Ranwara Road"));
}
Upvotes: 0
Reputation: 18923
Change this
googleMap = ((SupportMapFragment) getFragmentManager().findFragmentById(R.id.howtoreach_map)).getMap();
to
googleMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.howtoreach_map)).getMap();
Upvotes: 1