Aktivitas saya sedang mencoba membuat AlertDialog yang memerlukan Konteks sebagai parameter. Ini berfungsi seperti yang diharapkan jika saya menggunakan:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Namun, saya ragu menggunakan "ini" sebagai konteks karena potensi kebocoran memori ketika Aktivitas dihancurkan dan diciptakan kembali bahkan selama sesuatu yang sederhana seperti rotasi layar. Dari pos terkait di blog pengembang Android :
Ada dua cara mudah untuk menghindari kebocoran memori terkait konteks. Yang paling jelas adalah menghindari keluar dari konteks di luar ruang lingkupnya sendiri. Contoh di atas menunjukkan kasus referensi statis tetapi kelas dalam dan referensi implisit mereka ke kelas luar bisa sama-sama berbahaya. Solusi kedua adalah dengan menggunakan konteks Aplikasi. Konteks ini akan hidup selama aplikasi Anda hidup dan tidak tergantung pada siklus hidup kegiatan. Jika Anda berencana untuk menjaga objek berumur panjang yang membutuhkan konteks, ingat objek aplikasi. Anda dapat memperolehnya dengan mudah dengan menghubungi Context.getApplicationContext () atau Activity.getApplication ().
Tetapi untuk AlertDialog()
keduanya getApplicationContext()
atau getApplication()
dapat diterima sebagai Konteks, karena melemparkan pengecualian:
"Tidak dapat menambahkan jendela - token null bukan untuk aplikasi"
per referensi: 1 , 2 , 3 , dll.
Jadi, haruskah ini benar-benar dianggap sebagai "bug", karena kita secara resmi dinasihati untuk menggunakan Activity.getApplication()
dan tidak berfungsi seperti yang diiklankan?
Jim
sumber
Jawaban:
Alih-alih
getApplicationContext()
, gunakan sajaActivityName.this
.sumber
Listener
kelas sering anonim-batin, saya cenderung hanya melakukanfinal Context ctx = this;
dan saya pergi;)Menggunakan
this
tidak berhasil untuk saya, tetapiMyActivityName.this
berhasil. Semoga ini bisa membantu siapa saja yang tidak bisa mulaithis
bekerja.sumber
this
dari dalam kelas batin. Jika Anda ingin referensi instance kelas luar, Anda harus menentukannya, seperti yang Anda lakukan denganOuterClass.this
. Hanya menggunakanthis
selalu referensi instance kelas paling dalam.Anda dapat terus menggunakan
getApplicationContext()
, tetapi sebelum digunakan, Anda harus menambahkan tanda ini:,dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
dan kesalahan tidak akan ditampilkan.Tambahkan izin berikut ke manifes Anda:
sumber
Anda telah mengidentifikasi masalah dengan benar ketika Anda mengatakan "... untuk AlertDialog () tidak getApplicationContext () atau getApplication () dapat diterima sebagai suatu Konteks, karena melemparkan pengecualian: 'Tidak dapat menambahkan jendela - token null bukan untuk sebuah aplikasi'"
Untuk membuat Dialog, Anda memerlukan Konteks Aktivitas atau Konteks Layanan , bukan Konteks Aplikasi (keduanya getApplicationContext () dan getApplication () mengembalikan Konteks Aplikasi).
Inilah cara Anda mendapatkan Konteks Aktivitas :
(1) Dalam Suatu Kegiatan atau Layanan:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
(2) Dalam Fragmen:
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
Kebocoran memori bukan masalah yang intrinsik dengan referensi "ini", yang merupakan referensi objek untuk dirinya sendiri (yaitu referensi ke memori yang dialokasikan aktual untuk menyimpan data objek). Hal ini terjadi untuk setiap memori yang dialokasikan untuk yang Kolektor Sampah (GC) tidak dapat membebaskan setelah memori yang dialokasikan telah hidup lebih lama umur pakainya.
Sebagian besar waktu, ketika suatu variabel keluar dari ruang lingkup, memori akan direklamasi oleh GC. Namun, kebocoran memori dapat terjadi ketika referensi ke suatu objek yang dipegang oleh variabel, katakanlah "x", tetap ada bahkan setelah objek telah hidup lebih lama. Memori yang dialokasikan karenanya akan hilang selama "x" menyimpan referensi untuk itu karena GC tidak akan membebaskan memori selama memori itu masih dirujuk. Terkadang, kebocoran memori tidak terlihat karena rangkaian referensi ke memori yang dialokasikan. Dalam kasus seperti itu, GC tidak akan membebaskan memori sampai semua referensi ke memori tersebut telah dihapus.
Untuk mencegah kebocoran memori, periksa kode Anda untuk kesalahan logis yang menyebabkan memori yang dialokasikan direferensikan tanpa batas oleh "ini" (atau referensi lain). Ingatlah untuk memeriksa referensi rantai juga. Berikut adalah beberapa alat yang dapat Anda gunakan untuk membantu Anda menganalisis penggunaan memori dan menemukan kebocoran memori sial itu:
Kontrol Misi JRockit
Jubah pakaian
YourKit
AD4J
sumber
Dialog Anda seharusnya tidak menjadi "objek berumur panjang yang membutuhkan konteks". Dokumentasinya membingungkan. Pada dasarnya jika Anda melakukan sesuatu seperti:
(perhatikan statis )
Kemudian dalam suatu kegiatan di suatu tempat Anda lakukan
Anda mungkin akan membocorkan aktivitas asli selama rotasi atau serupa yang akan menghancurkan aktivitas. (Kecuali Anda membersihkan di onDestroy, tetapi dalam hal ini Anda mungkin tidak akan membuat objek Dialog statis)
Untuk beberapa struktur data masuk akal untuk membuatnya statis dan didasarkan pada konteks aplikasi, tetapi umumnya tidak untuk hal-hal terkait UI, seperti dialog. Jadi sesuatu seperti ini:
Tidak masalah dan tidak boleh membocorkan aktivitas karena mDialog akan dibebaskan dengan aktivitas karena tidak statis.
sumber
Saya harus mengirim konteks melalui konstruktor pada adaptor khusus yang ditampilkan dalam fragmen dan mengalami masalah ini dengan getApplicationContext (). Saya menyelesaikannya dengan:
this.getActivity().getWindow().getContext()
dalamonCreate
panggilan balik fragmen .sumber
dalam Aktivitas cukup gunakan:
dalam Fragmen:
sumber
Di
Activity
klik tombol yang menunjukkan kotak dialogBekerja untukku.
sumber
***** versi kotlin *****
Anda harus lulus
this@YourActivity
alih-alihapplicationContext
ataubaseContext
sumber
Sedikit hack: Anda dapat mencegah menghancurkan aktivitas Anda dengan GC (Anda tidak harus melakukannya, tetapi dapat membantu dalam beberapa situasi Jangan lupa untuk set.
contextForDialog
Untuknull
ketika itu tidak lagi diperlukan):sumber
Jika Anda menggunakan fragmen dan menggunakan pesan AlertDialog / Toast kemudian gunakan getActivity () dalam parameter konteks.
seperti ini
sumber
Cukup gunakan berikut ini:
UNTUK PENGGUNA JAWA
Jika Anda menggunakan aktivitas ->
AlertDialog.Builder builder = new AlertDialog.Builder(this);
ATAU
AlertDialog.Builder builder = new AlertDialog.Builder(your_activity.this);
Jika Anda menggunakan fragmen ->
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
UNTUK PENGGUNA KOTLIN
Jika Anda menggunakan aktivitas ->
val builder = AlertDialog.Builder(this)
ATAU
val builder = AlertDialog.Builder(this@your_activity.this)
Jika Anda menggunakan fragmen ->
val builder = AlertDialog.Builder(activity!!)
sumber
menambahkan
dan
"android.permission.SYSTEM_ALERT_WINDOW"/>
dalam manifesIni bekerja untuk saya sekarang. Setelah menutup dan membuka aplikasi, memberi saya kesalahan pada saat itu.
sumber
Saya menggunakan
ProgressDialog
dalam sebuah fragmen dan mendapatkan kesalahan ini saat meneruskangetActivity().getApplicationContext()
sebagai parameter konstruktor. Mengubahnya menjadigetActivity().getBaseContext()
tidak berhasil juga.Solusi yang berhasil bagi saya adalah lulus
getActivity()
; yaituprogressDialog = new ProgressDialog(getActivity());
sumber
Menggunakan
MyDialog md = new MyDialog(MyActivity.this.getParent());
sumber
Jika Anda berada di luar Aktivitas maka Anda perlu menggunakan fungsi "NameOfMyActivity.this" ini sebagai aktivitas Aktivitas, contoh:
sumber
Jika Anda menggunakan fragmen dan menggunakan
AlertDialog / Toast
pesan, gunakangetActivity()
dalam parameter konteks.Bekerja untukku.
Bersulang!
sumber
Cobalah untuk menggunakan konteks suatu kegiatan yang akan di bawah dialog. Tetapi berhati-hatilah ketika Anda menggunakan kata kunci "ini", karena itu tidak akan berfungsi setiap saat.
Sebagai contoh, jika Anda memiliki TabActivity sebagai host dengan dua tab, dan setiap tab adalah aktivitas lain, dan jika Anda mencoba membuat dialog dari salah satu tab (aktivitas) dan jika Anda menggunakan "ini", maka Anda akan mendapatkan pengecualian, dalam hal ini dialog kasus harus terhubung ke aktivitas host yang menampung semuanya dan terlihat. (Anda dapat mengatakan konteks aktivitas induk yang paling terlihat)
Saya tidak menemukan info ini dari dokumen apa pun tetapi dengan mencoba. Ini adalah solusi saya tanpa latar belakang yang kuat, Jika ada orang yang lebih dikenal, jangan ragu untuk berkomentar.
sumber
Untuk pembaca masa depan, ini akan membantu:
sumber
Dalam kasus kerja saya:
sumber
Atau kemungkinan lain adalah membuat Dialog sebagai berikut:
sumber
Saya pikir itu mungkin terjadi juga jika Anda mencoba untuk menampilkan dialog dari utas yang bukan utas UI utama.
Gunakan
runOnUiThread()
dalam kasus itu.sumber
Coba
getParent()
di tempat argumen konteks sepertiAlertDialog.Builder(getParent());
Harapan baru itu akan berhasil, itu berhasil untuk saya.sumber
Setelah melihat API, Anda dapat meneruskan dialog aktivitas Anda atau getActivity jika Anda berada di sebuah fragmen, lalu dengan paksa membersihkannya dengan dialog.dismiss () dalam metode pengembalian untuk mencegah kebocoran.
Meskipun tidak secara eksplisit dinyatakan di mana pun saya tahu, sepertinya Anda meneruskan dialog di OnClickHandlers hanya untuk melakukan ini.
sumber
Jika Dialog Anda dibuat di adaptor:
Lewati Aktivitas ke Konstruktor Adaptor:
Terima pada Adaptor:
Sekarang Anda dapat menggunakan Builder Anda
sumber
Inilah cara saya mengatasi kesalahan yang sama untuk aplikasi saya:
Menambahkan baris berikut setelah membuat dialog:
Anda tidak perlu memperoleh konteks. Ini sangat berguna jika Anda memunculkan dialog lain dari dialog yang muncul saat ini. Atau ketika tidak nyaman untuk mendapatkan konteks.
Semoga ini bisa membantu Anda dengan pengembangan aplikasi Anda.
David
sumber
sumber