Saya punya aplikasi dengan tiga tab.
Setiap tab memiliki tata letak .xml file sendiri. Main.xml memiliki fragmen peta sendiri. Itu yang muncul saat aplikasi pertama kali diluncurkan.
Semuanya berfungsi dengan baik kecuali ketika saya mengubah antar tab. Jika saya mencoba untuk beralih kembali ke tab fragmen peta, saya mendapatkan kesalahan ini. Beralih ke dan di antara tab lain berfungsi dengan baik.
Apa yang salah di sini?
Ini adalah kelas utama saya dan main.xml saya, serta kelas yang relevan yang saya gunakan (Anda juga akan menemukan log kesalahan di bagian bawah)
kelas utama
package com.nfc.demo;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.widget.Toast;
public class NFCDemoActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActionBar bar = getActionBar();
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
bar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);
bar.addTab(bar
.newTab()
.setText("Map")
.setTabListener(
new TabListener<MapFragment>(this, "map",
MapFragment.class)));
bar.addTab(bar
.newTab()
.setText("Settings")
.setTabListener(
new TabListener<SettingsFragment>(this, "settings",
SettingsFragment.class)));
bar.addTab(bar
.newTab()
.setText("About")
.setTabListener(
new TabListener<AboutFragment>(this, "about",
AboutFragment.class)));
if (savedInstanceState != null) {
bar.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0));
}
// setContentView(R.layout.main);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
public static class TabListener<T extends Fragment> implements
ActionBar.TabListener {
private final Activity mActivity;
private final String mTag;
private final Class<T> mClass;
private final Bundle mArgs;
private Fragment mFragment;
public TabListener(Activity activity, String tag, Class<T> clz) {
this(activity, tag, clz, null);
}
public TabListener(Activity activity, String tag, Class<T> clz,
Bundle args) {
mActivity = activity;
mTag = tag;
mClass = clz;
mArgs = args;
// Check to see if we already have a fragment for this tab,
// probably from a previously saved state. If so, deactivate
// it, because our initial state is that a tab isn't shown.
mFragment = mActivity.getFragmentManager().findFragmentByTag(mTag);
if (mFragment != null && !mFragment.isDetached()) {
FragmentTransaction ft = mActivity.getFragmentManager()
.beginTransaction();
ft.detach(mFragment);
ft.commit();
}
}
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if (mFragment == null) {
mFragment = Fragment.instantiate(mActivity, mClass.getName(),
mArgs);
ft.add(android.R.id.content, mFragment, mTag);
} else {
ft.attach(mFragment);
}
}
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
if (mFragment != null) {
ft.detach(mFragment);
}
}
public void onTabReselected(Tab tab, FragmentTransaction ft) {
Toast.makeText(mActivity, "Reselected!", Toast.LENGTH_SHORT)
.show();
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapFragment"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
kelas yang relevan (MapFragment.java)
package com.nfc.demo;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MapFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.main, container, false);
}
public void onDestroy() {
super.onDestroy();
}
}
kesalahan
android.view.InflateException: Binary XML file line #7:
Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at com.nfc.demo.MapFragment.onCreateView(MapFragment.java:15)
at android.app.Fragment.performCreateView(Fragment.java:1695)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:885)
at android.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1255)
at android.app.BackStackRecord.run(BackStackRecord.java:672)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1435)
at android.app.FragmentManagerImpl$1.run(FragmentManager.java:441)
at android.os.Handler.handleCallback(Handler.java:725)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5039)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException:
Binary XML file line #7: Duplicate id 0x7f040005, tag null, or
parent id 0xffffffff with another fragment for
com.google.android.gms.maps.MapFragment
at android.app.Activity.onCreateView(Activity.java:4722)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:680)
... 19 more
Jawaban:
Jawaban yang disarankan Matt berhasil, tetapi menyebabkan peta dibuat ulang dan digambar ulang, yang tidak selalu diinginkan. Setelah banyak coba-coba, saya menemukan solusi yang berfungsi untuk saya:
Untuk ukuran yang baik, inilah "map.xml" (R.layout.map) dengan R.id.mapFragment (android: id = "@ + id / mapFragment"):
Saya harap ini membantu, tetapi saya tidak dapat menjamin bahwa itu tidak memiliki efek buruk.
Sunting: Ada beberapa efek buruk, seperti ketika keluar dari aplikasi dan memulainya lagi. Karena aplikasi tidak sepenuhnya dimatikan (tetapi hanya ditidurkan di latar belakang), kode sebelumnya yang saya kirimkan akan gagal setelah memulai ulang aplikasi. Saya telah memperbarui kode ke sesuatu yang bekerja untuk saya, baik masuk & keluar dari peta dan keluar dan memulai kembali aplikasi, saya tidak terlalu senang dengan sedikit try-catch, tetapi tampaknya bekerja dengan cukup baik.
Ketika melihat jejak stack, terpikir oleh saya bahwa saya bisa memeriksa apakah fragmen peta ada di FragmentManager, tidak perlu untuk blok try-catch, kode diperbarui.Lebih banyak hasil pengeditan: Ternyata Anda memerlukan try-catch itu. Hanya memeriksa fragmen peta ternyata tidak berfungsi dengan baik. Blergh.
sumber
SupportMapFragment
in secara manualonDestroyView
.Masalahnya adalah bahwa apa yang Anda coba lakukan seharusnya tidak dilakukan. Anda seharusnya tidak menggembungkan fragmen di dalam fragmen lain. Dari dokumentasi Android :
Meskipun Anda mungkin dapat menyelesaikan tugas dengan retasan yang disajikan di sini, saya sangat menyarankan Anda untuk tidak melakukannya. Mustahil untuk memastikan bahwa peretasan ini akan menangani apa yang dilakukan oleh masing-masing OS Android baru ketika Anda mencoba mengembang tata letak untuk sebuah fragmen yang berisi fragmen lain.
Satu-satunya cara yang didukung Android untuk menambahkan fragmen ke fragmen lain adalah melalui transaksi dari manajer fragmen anak.
Cukup ubah tata letak XML Anda menjadi wadah kosong (tambahkan ID jika perlu):
Kemudian dalam
onViewCreated(View view, @Nullable Bundle savedInstanceState)
metode Fragmen :sumber
4.3
ketika menggunakanSupportMapFragment
didefinisikan dalam XML. Secara dinamis membuat fragmen dan menyuntikkannya ke tampilan wadah menyelesaikan masalah. Lihat jawaban SO ini .SupportMapFragment.newInstance();
developers.google.com/maps/documentation/android-api/mapSaya memiliki masalah yang sama dan mampu mengatasinya secara manual menghapus
MapFragment
dalamonDestroy()
metode dariFragment
kelas. Berikut adalah kode yang berfungsi dan referensiMapFragment
dengan ID dalam XML:Jika Anda tidak menghapus
MapFragment
secara manual, itu akan bertahan sehingga tidak membutuhkan banyak sumber daya untuk membuat ulang / menampilkan tampilan peta lagi. Tampaknya menjaga yang mendasarinyaMapView
bagus untuk beralih bolak-balik di antara tab, tetapi ketika digunakan dalam fragmen perilaku ini menyebabkan duplikatMapView
dibuat pada setiap baruMapFragment
dengan ID yang sama. Solusinya adalah dengan secara manual menghapusMapFragment
dan dengan demikian menciptakan kembali peta yang mendasarinya setiap kali fragmen meningkat.Saya juga mencatat ini dalam jawaban lain [ 1 ].
sumber
Ini jawaban saya:
1, Buat tata letak xml seperti berikut:
2, di kelas Fragmen, tambahkan google map secara terprogram.
sumber
mMapFragment.getMap();
kembalinull
. Ada yang tahu kenapa?Solusi saya:
sumber
Nyatakan objek SupportMapFragment secara global
Dalam metode onCreateView () tuliskan kode di bawah ini
Di onDestroyView () masukkan kode di bawah ini
Dalam file xml Anda, letakkan kode di bawah ini
Kode di atas menyelesaikan masalah saya dan berfungsi dengan baik
sumber
Saya akan merekomendasikan
replace()
daripadaattach()
/detach()
dalam penanganan tab Anda.Atau, beralih ke
ViewPager
. Berikut adalah contoh proyek yang menunjukkanViewPager
, dengan tab, menampung 10 peta.sumber
Solusi lain:
Itu saja, jika bukan nol Anda tidak perlu menginisialisasi ulang menghapusnya dari induk adalah langkah yang tidak perlu.
sumber
Saya kehilangan jam hari ini untuk menemukan alasannya, untungnya masalah ini bukan karena implementasi MapFragment, sayangnya, ini tidak berhasil karena fragmen bersarang hanya didukung melalui perpustakaan dukungan dari rev 11.
Implementasi saya memiliki aktivitas dengan actionbar (dalam mode tab) dengan dua tab (tanpa viewpager), yang satu memiliki peta dan yang lainnya memiliki daftar entri. Tentu saja saya sudah cukup naif untuk menggunakan MapFragment di dalam tab-fragmen saya, dan voila aplikasi mogok setiap kali saya kembali ke tab-peta.
(Masalah yang sama saya juga akan memiliki jika tab-fragmen saya akan mengembang tata letak yang mengandung fragmen lain).
Salah satu opsi adalah menggunakan MapView (bukan MapFragment), dengan beberapa overhead (lihat MapView Docs sebagai pengganti drop-in di layout.xml, opsi lain adalah menggunakan perpustakaan dukungan naik dari rev. 11 tetapi kemudian mengambil pendekatan programatik karena fragmen yang bersarang tidak didukung melalui tata letak atau hanya bekerja secara terprogram dengan menghancurkan fragmen secara eksplisit (seperti dalam jawaban dari Matt / Vidar), btw: efek yang sama dicapai dengan menggunakan MapView (opsi 1).
Tapi sebenarnya, saya tidak ingin kehilangan peta setiap kali saya tab, yaitu, saya ingin menyimpannya di memori dan pembersihan hanya setelah aktivitas ditutup, jadi saya memutuskan untuk hanya menyembunyikan / menampilkan peta saat menabrak, lihat FragmentTransaction / hide
sumber
Bagi mereka yang masih mengalami masalah ini, cara terbaik untuk memastikan Anda tidak mendapatkan kesalahan ini dengan Peta di Tab adalah untuk membuat Fragmen diperluas
SupportMapFragment
daripada bersarangSupportMapFragment
di dalam Fragmen yang digunakan untuk Tab.Saya baru saja menggunakan ini
ViewPager
denganFragmentPagerAdapter
, dengan SupportMapFragment di Tab ketiga.Berikut adalah struktur umum, perhatikan tidak perlu menimpa
onCreateView()
metode, dan tidak perlu mengembang tata letak xml:Hasil:
Berikut adalah kode kelas lengkap yang saya gunakan untuk menguji, yang mencakup Fragmen placeholder yang digunakan untuk dua Tab pertama, dan Fragmen Peta yang digunakan untuk Tab ketiga:
sumber
Saya menghargai semua jawaban tetapi saya menemukan solusi liner satu ini: Jika n Adalah Jumlah tab maka:
Contoh: Dalam hal disebutkan:
Lihat pager menerapkan antrian jadi, Anda tidak harus membiarkannya menghapus fragmen itu. onCreateView disebut hanya sekali.
sumber
Anda mengembalikan atau menggembungkan tata letak dua kali, cukup periksa untuk melihat apakah Anda hanya mengembang satu kali.
sumber
Fragmen bersarang saat ini tidak didukung. Coba Paket Dukungan, revisi 11 .
sumber
Sudahkah Anda mencoba mereferensikan
MapFragment
kelas khusus Anda di file tata letak?sumber
Jika Anda hanya akan menggunakan jawaban Vidar Wahlberg, Anda mendapatkan kesalahan saat Anda membuka aktivitas lain (misalnya) dan kembali ke peta. Atau dalam kasus saya buka aktivitas lain lalu dari aktivitas baru buka peta lagi (tanpa menggunakan tombol kembali). Tetapi ketika Anda menggabungkan solusi Vidar Wahlberg dan solusi Matt, Anda tidak akan memiliki pengecualian.
tata letak
Pecahan
sumber
Saya punya ini di viewPager dan crash karena setiap fragmen harus memiliki tag sendiri, duplikat tag atau id untuk fragmen yang sama tidak diperbolehkan.
sumber
Saya pikir ada beberapa bug di lib App-Compat sebelumnya untuk Fragmen anak. Saya mencoba @Vidar Wahlberg dan @ Matt dan mereka tidak bekerja untuk saya. Setelah memperbarui pustaka appcompat kode saya berjalan dengan sempurna tanpa usaha ekstra.
sumber
Hal yang Perlu Dicatat di sini adalah aplikasi Anda akan rusak parah di salah satu dari dua kasus: -
Berikut ini cuplikan kode sampel untuk penggunaan MapView yang benar
XML
Hasilnya terlihat seperti ini: -
Semoga ini bisa membantu Seseorang.
sumber
Dalam solusi ini Anda tidak perlu mengambil variabel statis;
sumber
Saya agak terlambat ke pesta tetapi tidak ada jawaban yang membantu saya dalam kasus saya. Saya menggunakan Google map sebagai SupportMapFragment dan PlaceAutocompleteFragment baik dalam fragmen saya. Karena semua jawaban menunjuk pada fakta bahwa masalahnya adalah dengan SupportMapFragment menjadi peta yang akan dibuat kembali dan digambar ulang. Tapi setelah menggali menemukan masalah saya sebenarnya dengan PlaceAutocompleteFragment
Jadi di sini adalah solusi untuk mereka yang menghadapi masalah ini karena SupportMapFragment dan SupportMapFragment
Dan di onDestroyView hapus SupportMapFragment dan SupportMapFragment
sumber
Coba atur id (android: id = "@ + id / maps_dialog") untuk tata letak induk mapView Anda. Bekerja untukku.
sumber
Siapa pun yang datang ke sini sekarang yang mendapatkan jenis kesalahan ini ketika membuka
Dialog
atau lainnyaFragment
dengan Google PlacesAutocompleteSupportFragment
, coba ini satu-liner (saya tidak tahu seberapa aman ini tetapi ini berfungsi untuk saya):autocompleteFragment.getFragmentManager().beginTransaction().remove(autocompleteFragment).commit();
sebelum Anda menolak / menghancurkan fragmen Anda.
sumber
Mengapa Anda tidak menyisipkan peta menggunakan objek MapView alih-alih MapFragment? Saya tidak yakin apakah ada batasan dalam MapView, meskipun saya merasa terbantu.
sumber