问题
All more or less works. But if the LocationFragment is recreated, the application falls.
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest package="XX.XX.XXXXXXXX"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key"/>
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
<activity
android:name=".ui.activities.LaunchActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.FullScreen"
android:windowSoftInputMode="stateAlwaysHidden|adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ui.activities.MainActivity"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"/>
<activity android:name=".ui.activities.SettingsActivity"
android:screenOrientation="portrait"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"/>
<activity android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:label="@string/app_name" />
<meta-data
android:name="com.crashlytics.ApiKey"
android:value="XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"/>
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id"/>
</application>
public enum GeolocationState
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
public enum GeolocationState {
INST;
private static final String TAG = "Geolocation";
public static final long WAITING_TIME_MILLIS = 3000L;
public static final float ACCURANCY_IN_METERS = 3f;
private Context context;
private LocationManager locationManager;
private Geocoder geocoder;
public void init(Context context) {
this.context = context;
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
geocoder = new Geocoder(context, Locale.getDefault());
}
public Address getAddress(Location location) {
try {
List<Address> addressList = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
if (addressList != null && !addressList.isEmpty()) {
return addressList.get(0);
}
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(context, "Помилка геопозиціонування", Toast.LENGTH_SHORT).show();
}
return null;
}
public void mapPositioning(GoogleMap mMap, double latitude, double longitude){
LatLng coordinates = new LatLng(latitude, longitude);
if(mMap!=null) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(coordinates, 13));
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(coordinates)
.zoom(17)
.bearing(90)
.tilt(0)
.build();
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}
public LocationManager getLocationManager() {
return locationManager;
}
}
public class LocationFragment
import android.location.Address;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import java.text.DecimalFormat;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import xx.xx.xxxxxxxx.R;
import xx.xx.xxxxxxxx.services.ClaimState;
import xx.xx.xxxxxxxx.services.GeolocationState;
import xx.xx.xxxxxxxx.ui.activities.MainActivity;
public class LocationFragment extends BaseFragment implements OnMapReadyCallback, GoogleMap.OnMyLocationButtonClickListener{
private static final String TAG = LocationFragment.class.getName();
private GoogleMap mMap;
@BindView(R.id.positioning_text_view)
TextView positioningText;
@BindView(R.id.next_button)
Button nextButton;
private Unbinder unbinder;
public static Fragment newInstance() {
return new LocationFragment();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_location, container, false);
//**INFLATE ERROR IN rootView WHEN YOU MOVE QUICKLY BETWEEN FRAGMENTS**
unbinder = ButterKnife.bind(this, rootView);
SupportMapFragment fragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map);
fragment.getMapAsync(this);
return rootView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
((MainActivity) getActivity()).moveToNext();
}
});
nextButton.setVisibility(View.GONE);
}
@Override
public void onResume() {
super.onResume();
GeolocationState.INST.getLocationManager().requestLocationUpdates(
LocationManager.GPS_PROVIDER,
GeolocationState.WAITING_TIME_MILLIS,
GeolocationState.ACCURANCY_IN_METERS,
locationListener);
}
@Override
public void onPause() {
super.onPause();
GeolocationState.INST.getLocationManager().removeUpdates(locationListener);
}
private LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
if(location != null && mMap != null) {
Address address = GeolocationState.INST.getAddress(location);
if (address != null) {
ClaimState.INST.getClaim().setCity(address.getLocality());
ClaimState.INST.getClaim().setAddress(address.getAddressLine(0));
positioningText.setText(ClaimState.INST.getFullAddress());
nextButton.setVisibility(View.VISIBLE);
}
DecimalFormat df = new DecimalFormat("#.######");
ClaimState.INST.getClaim().setLatitude(df.format(location.getLatitude()).replace(",", "."));
ClaimState.INST.getClaim().setLongitude(df.format(location.getLongitude()).replace(",", "."));
GeolocationState.INST.mapPositioning(mMap, location.getLatitude(), location.getLongitude());
}
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
};
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
if(mMap != null) {
mMap.setMyLocationEnabled(true);
mMap.setOnMyLocationButtonClickListener(this);
mMap.getUiSettings().setCompassEnabled(false);
}
}
@Override
public boolean onMyLocationButtonClick() {
return false;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser && isResumed()){
Toast toast = Toast.makeText(getContext(), "Bla-bla-bla", Toast.LENGTH_LONG);
LinearLayout layout = (LinearLayout) toast.getView();
if (layout.getChildCount() > 0) {
TextView tv = (TextView) layout.getChildAt(0);
tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL);
}
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
}
}
@Override public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}
fragment_location.xml (Layout)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/bottomPanel"
android:layout_width="match_parent"
android:layout_height="130dp"
android:layout_alignParentBottom="true"
android:background="@color/primaryColor">
<TextView
android:id="@+id/positioning_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dp"
android:text="@string/positioning_in_progress"
android:textColor="@android:color/white"
android:textSize="17sp"/>
<Button
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:background="@drawable/button_background"
android:paddingLeft="45dp"
android:paddingRight="45dp"
android:text="@string/next"
android:textAllCaps="false"
android:textSize="17sp"
/>
</RelativeLayout>
<fragment
android:id="@+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/bottomPanel"
android:layout_alignParentTop="true" />
</RelativeLayout>
printStackTrace
07-28 13:17:57.257 28765-28765/xx.xx.xxxxxxxx E/AndroidRuntime: FATAL EXCEPTION: main
Process: xx.xx.xxxxxxxx, PID: 28765
android.view.InflateException: Binary XML file line #40: Binary XML file line #40: Error inflating class fragment
at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at xx.xx.xxxxxxxx.ui.fragments.LocationFragment.onCreateView(LocationFragment.java:55)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1430)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:732)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1177)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)
at android.support.v4.view.ViewPager$3.run(ViewPager.java:254)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: android.view.InflateException: Binary XML file line #40: Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:782)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:835)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at xx.xx.xxxxxxxx.ui.fragments.LocationFragment.onCreateView(LocationFragment.java:55)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1430)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:732)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617)
at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:570)
at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1177)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)
at android.support.v4.view.ViewPager$3.run(ViewPager.java:254)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:603)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Caused by: java.lang.IllegalArgumentException: Binary XML file line #40: Duplicate id 0x7f0e0104, tag null, or parent id 0xffffffff with another fragment for com.google.android.gms.maps.SupportMapFragment
at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2293)
at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:186)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:746)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:835)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:798)
at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at xx.xx.xxxxxxxx.ui.fragments.LocationFragment.onCreateView(LocationFragment.java:55)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1430)
.....
UPD: I have 4 fragments
CaptureFragment(1) - TypeFragment(2) - LocationFragment(3) - OverviewFragment(4)
When I quickly move between:
TypeFragment - LocationFragment
or
LocationFragment - OverviewFragment
all is ok.
But if I move CaptureFragment(1) -> TypeFragment(2) -> LocationFragment(3)
then
LocationFragment(3) -> TypeFragment(2) -> CaptureFragment(1)
then
CaptureFragment(1) -> TypeFragment(2)
it breaks.
I know that when the TypeFragment is created, it is created and the next activity CaptureFragment. At this point, the application falls.
Does anyone know how to fix it?
回答1:
This is how I load my map layout in a fragment:
private View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null)
parent.removeView(view);
}
try {
view = inflater.inflate(R.layout.map_fragment_location, container, false);
} catch (InflateException e) {
/* map is already there, just return view as it is */
}
ButterKnife.bind(this, view);
SupportMapFragment mapFragment = (SupportMapFragment)getChildFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
return view;
}
This helps check your layout and if it already exists, you don't have to create again!
Please try it and let me know how it goes!
回答2:
It helped me
private static View rootView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (rootView == null) {
rootView = inflater.inflate(R.layout.fragment_location, container, false);
}
unbinder = ButterKnife.bind(this, rootView);
return rootView;
}
LocationFragment and SupportMapFragment work correctly.
Maybe it's not the best solution. If you know a better solution, please share it.
来源:https://stackoverflow.com/questions/38637778/android-inflateexception-error-in-fragment-layout-with-supportmapfragment-recre