Dalam laporan kesalahan konsol pengembang terkadang saya melihat laporan dengan masalah NPE. Saya tidak mengerti apa yang salah dengan kode saya. Pada emulator dan aplikasi perangkat saya berfungsi dengan baik tanpa forceclose, namun beberapa pengguna mendapatkan NullPointerException di kelas fragmen ketika metode getActivity () dipanggil.
Aktivitas
pulic class MyActivity extends FragmentActivity{
private ViewPager pager;
private TitlePageIndicator indicator;
private TabsAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
pager = (ViewPager) findViewById(R.id.pager);
indicator = (TitlePageIndicator) findViewById(R.id.indicator);
adapter = new TabsAdapter(getSupportFragmentManager(), false);
adapter.addFragment(new FirstFragment());
adapter.addFragment(new SecondFragment());
indicator.notifyDataSetChanged();
adapter.notifyDataSetChanged();
// push first task
FirstTask firstTask = new FirstTask(MyActivity.this);
// set first fragment as listener
firstTask.setTaskListener((TaskListener) adapter.getItem(0));
firstTask.execute();
}
indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment currentFragment = adapter.getItem(position);
((Taskable) currentFragment).executeTask();
}
@Override
public void onPageScrolled(int i, float v, int i1) {}
@Override
public void onPageScrollStateChanged(int i) {}
});
}
Kelas AsyncTask
public class FirstTask extends AsyncTask{
private TaskListener taskListener;
...
@Override
protected void onPostExecute(T result) {
...
taskListener.onTaskComplete(result);
}
}
Kelas fragmen
public class FirstFragment extends Fragment immplements Taskable, TaskListener{
public FirstFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_view, container, false);
}
@Override
public void executeTask() {
FirstTask firstTask = new FirstTask(MyActivity.this);
firstTask.setTaskListener(this);
firstTask.execute();
}
@Override
public void onTaskComplete(T result) {
// NPE is here
Resources res = getActivity().getResources();
...
}
}
Mungkin kesalahan ini terjadi ketika aplikasi dilanjutkan dari latar belakang. Dalam hal ini bagaimana saya harus menangani situasi ini dengan benar?
android
android-fragments
android-activity
android-asynctask
nullpointerexception
Georgy Gobozov
sumber
sumber
Jawaban:
Tampaknya saya menemukan solusi untuk masalah saya. Penjelasan yang sangat bagus diberikan di sini dan di sini . Ini contoh saya:
Gagasan utama dalam kode ini adalah, saat menjalankan aplikasi Anda secara normal, Anda membuat fragmen baru dan meneruskannya ke adaptor. Ketika Anda melanjutkan manajer fragmen aplikasi Anda sudah memiliki instance fragmen ini dan Anda perlu mendapatkannya dari manajer fragmen dan meneruskannya ke adaptor.
MEMPERBARUI
Juga, ini adalah praktik yang baik ketika menggunakan fragmen untuk memeriksa isAdded sebelum getActivity () dipanggil. Ini membantu menghindari pengecualian penunjuk nol ketika fragmen terlepas dari aktivitas. Misalnya, suatu aktivitas bisa berisi fragmen yang mendorong tugas async. Ketika tugas selesai, pendengar onTaskComplete dipanggil.
Jika kami membuka fragmen, mendorong tugas, dan kemudian dengan cepat tekan kembali untuk kembali ke aktivitas sebelumnya, ketika tugas selesai, ia akan mencoba mengakses aktivitas di onPostExecute () dengan memanggil metode getActivity (). Jika aktivitas sudah terlepas dan pemeriksaan ini tidak ada:
kemudian aplikasi macet.
sumber
isAdded()
sebelum setiap akses ... membuat kode jelek.if(isAdded())
atauif(getActivity() != null)
Oke, saya tahu bahwa pertanyaan ini sebenarnya sudah diselesaikan tetapi saya memutuskan untuk membagikan solusi saya untuk ini. Saya telah membuat kelas induk abstrak untuk
Fragment
:Seperti yang Anda lihat, saya telah menambahkan pendengar jadi, setiap kali saya harus mendapatkan
Fragments
Activity
alih-alih standargetActivity()
, saya harus meneleponsumber
Cara terbaik untuk menghilangkannya adalah dengan menyimpan referensi aktivitas saat
onAttach
dipanggil dan menggunakan referensi aktivitas di mana pun dibutuhkan, misalnyaDiedit, karena
onAttach(Activity)
didepresiasi & sekarangonAttach(Context)
sedang digunakansumber
getActivity()
mengembalikan nol, itu karena Anda tidak lagi dalam suatu kegiatan. Ini adalah solusi yang kotor.Jangan panggil metode dalam Fragmen yang memerlukan getActivity () hingga onStart di Aktivitas induk.
sumber
Saya telah berjuang melawan masalah semacam ini untuk sementara waktu, dan saya pikir saya telah menemukan solusi yang dapat diandalkan.
Sangat sulit untuk mengetahui pasti bahwa
this.getActivity()
tidak akan kembalinull
untukFragment
, terutama jika Anda berurusan dengan segala jenis perilaku jaringan yang memberikan kode Anda cukup waktu untuk menarikActivity
referensi.Dalam solusi di bawah ini, saya mendeklarasikan kelas manajemen kecil yang disebut
ActivityBuffer
. Pada dasarnya, iniclass
berkaitan dengan mempertahankan referensi yang dapat diandalkan untuk memilikiActivity
, dan berjanji untuk mengeksekusiRunnable
dalamActivity
konteks yang valid setiap kali ada referensi yang valid tersedia. TheRunnable
s dijadwalkan untuk eksekusi pada UI Thread segera jikaContext
tersedia, jika tidak eksekusi ditangguhkan sampai yangContext
siap.Dalam hal implementasinya, kita harus berhati-hati untuk menerapkan metode siklus hidup agar sesuai dengan perilaku yang dijelaskan di atas oleh Pawan M :
Akhirnya, di area mana pun di dalam diri Anda yang
Fragment
menyatakanBaseFragment
bahwa Anda tidak dapat dipercaya tentang panggilan untukgetActivity()
, cukup lakukan panggilan kethis.getActivityBuffer().safely(...)
dan nyatakanActivityBuffer.IRunnable
untuk tugas itu!Konten Anda
void run(final Activity pActivity)
kemudian dijamin untuk dieksekusi di sepanjang UI Thread.The
ActivityBuffer
kemudian dapat digunakan sebagai berikut:sumber
sumber
Saya tahu ini adalah pertanyaan lama tetapi saya pikir saya harus memberikan jawaban saya karena masalah saya tidak diselesaikan oleh orang lain.
pertama-tama: saya menambahkan fragmen secara dinamis menggunakan fragmentTransactions. Kedua: fragmen saya dimodifikasi menggunakan AsyncTasks (permintaan DB pada server). Ketiga: fragmen saya tidak dipakai pada aktivitas mulai Keempat: saya menggunakan instantiasi fragmen khusus "buat atau muat" untuk mendapatkan variabel fragmen. Keempat: aktivitas diciptakan kembali karena perubahan orientasi
Masalahnya adalah saya ingin "menghapus" fragmen karena jawaban kueri, tetapi fragmen itu dibuat secara tidak benar sebelumnya. Saya tidak tahu mengapa, mungkin karena "komit" dilakukan nanti, fragmen belum ditambahkan ketika tiba saatnya untuk menghapusnya. Oleh karena itu getActivity () mengembalikan nol.
Solusi: 1) Saya harus memeriksa bahwa saya benar mencoba untuk menemukan contoh pertama dari fragmen sebelum membuat yang baru 2) Saya harus meletakkan serRetainInstance (true) pada fragmen itu agar tetap melalui perubahan orientasi (tidak ada backstack) dibutuhkan karena itu tidak ada masalah) 3) Alih-alih "membuat ulang atau mendapatkan fragmen lama" sebelum "menghapusnya", saya langsung meletakkan fragmen itu di awal kegiatan. Instantiasi saat aktivitas dimulai alih-alih "memuat" (atau instantiasi) variabel fragmen sebelum menghapusnya mencegah masalah getActivity.
sumber
Di Kotlin Anda dapat mencoba cara ini untuk menangani getActivity () kondisi nol.
Ini akan memeriksa aktivitas adalah nol atau tidak dan jika tidak nol maka jalankan kode dalam.
sumber