使用TabLayout在ViewPager中的Google地图片段中膨胀exception

我制作了一个应用程序,在该应用程序中,我在我的位置显示了带有GPS位置标记的Google地图。 该地图位于第一个标签上,另外还有两个标签,如下图所示

在这里输入图像说明

现在我面临一个问题,即当我从标签1移动到标签2,然后到标签1它完美的作品,但当我移动到标签3,然后移回标签1或标签2,应用程序崩溃,并给予以下LogCatexception

 01-27 18:35:26.190 9414-9414/com.example.accurat.faisal E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.accurat.faisal, PID: 9414 android.view.InflateException: Binary XML file line #26: Binary XML file line #26: Error inflating class fragment at android.view.LayoutInflater.inflate(LayoutInflater.java:551) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at com.example.accurat.faisal.MyLocation.onCreateView(MyLocation.java:62) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2184) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1298) at android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(FragmentManager.java:2323) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2136) at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2092) at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1969) at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:620) at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143) at android.support.v4.view.ViewPager.populate(ViewPager.java:1268) at android.support.v4.view.ViewPager.populate(ViewPager.java:1116) at android.support.v4.view.ViewPager$3.run(ViewPager.java:273) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911) at android.view.Choreographer.doCallbacks(Choreographer.java:686) at android.view.Choreographer.doFrame(Choreographer.java:619) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 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:7325) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: android.view.InflateException: Binary XML file line #26: Error inflating class fragment at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:794) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.inflate(LayoutInflater.java:527) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at com.example.accurat.faisal.MyLocation.onCreateView(MyLocation.java:62) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2184) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1298) at android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(FragmentManager.java:2323) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2136) at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2092) at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1969) at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:620) at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143) at android.support.v4.view.ViewPager.populate(ViewPager.java:1268) at android.support.v4.view.ViewPager.populate(ViewPager.java:1116) at android.support.v4.view.ViewPager$3.run(ViewPager.java:273) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911) at android.view.Choreographer.doCallbacks(Choreographer.java:686) at android.view.Choreographer.doFrame(Choreographer.java:619) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 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:7325) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: java.lang.IllegalArgumentException: Binary XML file line #26: Duplicate id 0x7f10010d, 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:3364) at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:47) at android.view.LayoutInflater$FactoryMerger.onCreateView(LayoutInflater.java:192) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:758) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.inflate(LayoutInflater.java:527) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at com.example.accurat.faisal.MyLocation.onCreateView(MyLocation.java:62) at android.support.v4.app.Fragment.performCreateView(Fragment.java:2184) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1298) at android.support.v4.app.FragmentManagerImpl.moveFragmentsToInvisible(FragmentManager.java:2323) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2136) at android.support.v4.app.FragmentManagerImpl.optimizeAndExecuteOps(FragmentManager.java:2092) at android.support.v4.app.FragmentManagerImpl.execSingleAction(FragmentManager.java:1969) at android.support.v4.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:620) at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:143) at android.support.v4.view.ViewPager.populate(ViewPager.java:1268) at android.support.v4.view.ViewPager.populate(ViewPager.java:1116) at android.support.v4.view.ViewPager$3.run(ViewPager.java:273) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911) at android.view.Choreographer.doCallbacks(Choreographer.java:686) at android.view.Choreographer.doFrame(Choreographer.java:619) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897) 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:7325) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 

它显示在下面的错误点:

 // inflat and return the layout View rootView = inflater.inflate(R.layout.my_location, container, false); 

无论我select任何选项卡,它总是显示我上面的错误,即当我去我的pictures选项卡,并返回到cameramy location选项卡它总是显示我上面的错误。

以下是我的布局

 <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.accurat.faisal"> <permission android:name="com.example.accurat.faisal.permission.MAPS_RECEIVE" android:protectionLevel="signature"/> <uses-permission android:name="com.example.accurat.faisal.permission.MAPS_RECEIVE"/> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-feature android:glEsVersion="0x00020000" android:required="true" /> <application android:name="" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <meta-data android:name="com.google.android.geo.API_KEY" android:value="MY_KEY" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> 

以下是我的布局代码

 <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:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.accurat.faisal.MyLocation$PlaceholderFragment"> <TextView android:id="@+id/section_label" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignBottom="@+id/section_label" android:id="@+id/textView" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:textAppearance="@style/TextAppearance.AppCompat.Body2" /> <fragment 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:id="@+id/map" tools:context="com.example.app.MyLocation" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_below="@+id/section_label" /> 

我已经search并find了很多答案( 1,2,3 ),但无法find任何帮助

我坚持下去,任何帮助将不胜感激

Solutions Collecting From Web of "使用TabLayout在ViewPager中的Google地图片段中膨胀exception"

注意:当布局包含<fragment>时,不能将布局充气到碎片中。

只有在dynamic添加到片段时才支持嵌套片段。

这将解决您的问题,但请注意可以有更好的,

  • 在地图片段中保留静态视图
  • onCreateView检查视图为空,第一次它将是空的
  • 如果有一个视图(在第一次加载后),你需要删除它,所以每当片段被第一次调用时
  • 然后你可以设置你的视图(你的my_location)为片段,所以你不会得到一个嵌套的片段问题

例:

  private static View view; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (view != null) { ViewGroup viewGroupParent = (ViewGroup) view.getParent(); if (viewGroupParent != null) viewGroupParent.removeView(view); } try { view = inflater.inflate(R.layout.yourLayoutWithMap, container, false); } catch (Exception e) { // map is already there } return view; } 

在这里find相关的答案

这个问题是由一个MapFragment作为包含Google Map的根ViewPager Fragment的嵌套片段引起的。

解决这个问题的最简单最直接的方法是通过使ViewPager中的片段直接扩展SupportMapFragment

这是一个工作的例子。

首先,包含在第一个标签中显示Google Map的ViewPager适配器的活动:

 public class MainActivity extends AppCompatActivity { ViewPager viewPager; PagerAdapter pagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); // Get the ViewPager and set it's PagerAdapter so that it can display items viewPager = (ViewPager) findViewById(R.id.viewpager); pagerAdapter = new PagerAdapter(getSupportFragmentManager(), MainActivity.this); viewPager.setAdapter(pagerAdapter); // Give the TabLayout the ViewPager TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout); tabLayout.setupWithViewPager(viewPager); // Iterate over all tabs and set the custom view for (int i = 0; i < tabLayout.getTabCount(); i++) { TabLayout.Tab tab = tabLayout.getTabAt(i); tab.setCustomView(pagerAdapter.getTabView(i)); } } class PagerAdapter extends FragmentPagerAdapter { String tabTitles[] = new String[] { "Tab One", "Tab Two", "Tab Three", }; public Fragment[] fragments = new Fragment[tabTitles.length]; Context context; public PagerAdapter(FragmentManager fm, Context context) { super(fm); this.context = context; } @Override public int getCount() { return tabTitles.length; } @Override public Fragment getItem(int position) { switch (position) { case 0: return new MapFragment(); case 1: return new BlankFragment(); case 2: return new BlankFragment(); } return null; } @Override public CharSequence getPageTitle(int position) { // Generate title based on item position return tabTitles[position]; } public View getTabView(int position) { View tab = LayoutInflater.from(MainActivity.this).inflate(R.layout.custom_tab, null); TextView tv = (TextView) tab.findViewById(R.id.custom_text); tv.setText(tabTitles[position]); return tab; } //This populates your Fragment reference array: @Override public Object instantiateItem(ViewGroup container, int position) { Fragment createdFragment = (Fragment) super.instantiateItem(container, position); fragments[position] = createdFragment; return createdFragment; } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { if (requestCode == MapFragment.MY_PERMISSIONS_REQUEST_LOCATION){ MapFragment mapFragment = (MapFragment) pagerAdapter.fragments[0]; if (mapFragment != null) { mapFragment.onRequestPermissionsResult(requestCode, permissions, grantResults); } } else { super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } } 

activity_main.xml中:

 <?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.danielnugent.mapapplication.MainActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay" android:elevation="6dp"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" android:elevation="0dp" /> <android.support.design.widget.TabLayout android:id="@+id/tab_layout" app:tabMode="fixed" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/toolbar" android:background="?attr/colorPrimary" android:elevation="0dp" app:tabTextColor="#d3d3d3" app:tabSelectedTextColor="#ffffff" app:tabIndicatorColor="#ff00ff" android:minHeight="?attr/actionBarSize" /> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="fill_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.design.widget.CoordinatorLayout> 

custom_tab.xml:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/custom_text" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="?attr/selectableItemBackground" android:gravity="center" android:textSize="16dip" android:textColor="#ffffff" android:maxLines="1" /> </LinearLayout> 

MapFragment(从我这里的其他答案 ),它直接扩展SupportMapFragment,并不需要膨胀任何XML布局:

 public class MapFragment extends SupportMapFragment implements OnMapReadyCallback, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener { GoogleMap mGoogleMap; SupportMapFragment mapFrag; LocationRequest mLocationRequest; GoogleApiClient mGoogleApiClient; Location mLastLocation; Marker mCurrLocationMarker; @Override public void onResume() { super.onResume(); setUpMapIfNeeded(); } private void setUpMapIfNeeded() { if (mGoogleMap == null) { getMapAsync(this); } } @Override public void onPause() { super.onPause(); //stop location updates when Activity is no longer active if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); } } @Override public void onMapReady(GoogleMap googleMap) { mGoogleMap=googleMap; mGoogleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID); //Initialize Google Play Services if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { //Location Permission already granted buildGoogleApiClient(); mGoogleMap.setMyLocationEnabled(true); } else { //Request Location Permission checkLocationPermission(); } } else { buildGoogleApiClient(); mGoogleMap.setMyLocationEnabled(true); } } protected synchronized void buildGoogleApiClient() { mGoogleApiClient = new GoogleApiClient.Builder(getActivity()) .addConnectionCallbacks(this) .addOnConnectionFailedListener(this) .addApi(LocationServices.API) .build(); mGoogleApiClient.connect(); } @Override public void onConnected(Bundle bundle) { mLocationRequest = new LocationRequest(); mLocationRequest.setInterval(1000); mLocationRequest.setFastestInterval(1000); mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); } } @Override public void onConnectionSuspended(int i) {} @Override public void onConnectionFailed(ConnectionResult connectionResult) {} @Override public void onLocationChanged(Location location) { mLastLocation = location; if (mCurrLocationMarker != null) { mCurrLocationMarker.remove(); } //Place current location marker LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude()); MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(latLng); markerOptions.title("Current Position"); markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA)); mCurrLocationMarker = mGoogleMap.addMarker(markerOptions); //move map camera mGoogleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng)); mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(11)); //optionally, stop location updates if only current location is needed if (mGoogleApiClient != null) { LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this); } } public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99; private void checkLocationPermission() { if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // Should we show an explanation? if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) { // Show an explanation to the user *asynchronously* -- don't block // this thread waiting for the user's response! After the user // sees the explanation, try again to request the permission. new AlertDialog.Builder(getActivity()) .setTitle("Location Permission Needed") .setMessage("This app needs the Location permission, please accept to use location functionality") .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //Prompt the user once explanation has been shown ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION ); } }) .create() .show(); } else { // No explanation needed, we can request the permission. ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION ); } } } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_LOCATION: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // permission was granted, yay! Do the // location-related task you need to do. if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (mGoogleApiClient == null) { buildGoogleApiClient(); } mGoogleMap.setMyLocationEnabled(true); } } else { // permission denied, boo! Disable the // functionality that depends on this permission. Toast.makeText(getActivity(), "permission denied", Toast.LENGTH_LONG).show(); } return; } // other 'case' lines to check for other // permissions this app might request } } } 

结果:

在这里输入图像说明

不要为地图使用片段,请尝试使用MapView 。 有很多关于如何做到这一点的教程。

还要更改ViewPager的屏幕外页面限制。 你可以查看这篇文章的更多信息。 这样你的标签就不会在屏幕之外被重新创build。

我尊重所有的答案,但我发现这一个class轮解决scheme:如果n是选项卡数然后:

mViewPager.setOffscreenPageLimit(N);

例如:如上所述:

mViewPager.setOffscreenPageLimit(2);

查看寻呼机实现一个队列,所以你不必让它去除那个片段。 onCreateView只被调用一次。