Исправить исключение в фрагменте карты Google в ViewPager с помощью TabLayout

Я сделал приложение, в котором я отобразил карту Google с маркером местоположения GPS в моем местоположении. Эта карта находится на первой вкладке, и у меня также есть две другие вкладки, как показано на рисунке ниже

Введите описание изображения здесь

Теперь я столкнулся с проблемой, то есть, когда я перехожу от вкладки 1 к вкладке 2, а затем к вкладке 1, она отлично работает, но когда я перехожу на вкладку 3, а затем перехожу на вкладку 1 или вкладку 2, приложение вылетает и дает следующее Исключение в LogCat :

 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); 

Независимо от того, выбираю ли я какую-либо вкладку, она всегда показывает мне ошибку в приведенной выше строке, т. Е. Когда я перехожу на вкладку «Мои pictures » и возвращаюсь на camera или на вкладку my 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" /> 

Я искал и нашел много ответов на них ( 1 , 2 , 3 ), но не смог найти никакой помощи на нем

Я придерживаюсь этого, любая помощь будет оценена

Solutions Collecting From Web of "Исправить исключение в фрагменте карты Google в ViewPager с помощью TabLayout"

Примечание. Вы не можете раздувать макет во фрагмент, если этот макет включает <фрагмент>.

Вложенные фрагменты поддерживаются только при динамическом добавлении к фрагменту.

Это решит вашу проблему, но заметьте, что могут быть лучшие,

  • Сохранять статический вид в фрагменте карты
  • В 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; } 

Найдите ответы на запросы здесь

Эта проблема вызвана тем, что MapFragment является вложенным фрагментом корневого фрагмента ViewPager, который содержит карту Google.

Самый чистый и самый простой способ исправить это заключается в том, что Fragment, который входит в ViewPager, напрямую поддерживает SupportMapFragment .

Вот рабочий пример.

Во-первых, активность, которая содержит адаптер ViewPager, который показывает карту Google на первой вкладке:

 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. Вы можете проверить эту статью для получения дополнительной информации. Таким образом, ваши вкладки не будут воссозданы, когда они находятся вне экрана.

Я уважаю все ответы, но я нашел это одно решение для линейки: Если n – количество вкладок, то:

mViewPager.setOffscreenPageLimit (п);

Пример: В случае упоминания:

mViewPager.setOffscreenPageLimit (2);

View pager реализует очередь, поэтому вам не нужно удалять этот фрагмент. OnCreateView вызывается только один раз.