Program saya melakukan beberapa aktivitas jaringan di utas latar belakang. Sebelum memulai, muncul dialog progres. Dialog diberhentikan pada pawang. Ini semua berfungsi dengan baik, kecuali ketika orientasi layar berubah saat dialog naik (dan utas latar berjalan). Pada titik ini aplikasi mengalami crash, atau deadlock, atau masuk ke tahap aneh di mana aplikasi tidak bekerja sama sekali sampai semua utas telah terbunuh.
Bagaimana saya bisa menangani perubahan orientasi layar dengan anggun?
Kode contoh di bawah ini kira-kira cocok dengan yang dilakukan oleh program saya yang sebenarnya:
public class MyAct extends Activity implements Runnable {
public ProgressDialog mProgress;
// UI has a button that when pressed calls send
public void send() {
mProgress = ProgressDialog.show(this, "Please wait",
"Please wait",
true, true);
Thread thread = new Thread(this);
thread.start();
}
public void run() {
Thread.sleep(10000);
Message msg = new Message();
mHandler.sendMessage(msg);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mProgress.dismiss();
}
};
}
Tumpukan:
E/WindowManager( 244): Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): android.view.WindowLeaked: Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): at android.view.ViewRoot.<init>(ViewRoot.java:178)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:147)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:90)
E/WindowManager( 244): at android.view.Window$LocalWindowManager.addView(Window.java:393)
E/WindowManager( 244): at android.app.Dialog.show(Dialog.java:212)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:103)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:91)
E/WindowManager( 244): at MyAct.send(MyAct.java:294)
E/WindowManager( 244): at MyAct$4.onClick(MyAct.java:174)
E/WindowManager( 244): at android.view.View.performClick(View.java:2129)
E/WindowManager( 244): at android.view.View.onTouchEvent(View.java:3543)
E/WindowManager( 244): at android.widget.TextView.onTouchEvent(TextView.java:4664)
E/WindowManager( 244): at android.view.View.dispatchTouchEvent(View.java:3198)
Saya telah mencoba untuk mengabaikan dialog progres di onSaveInstanceState, tetapi itu hanya mencegah crash segera. Utas latar belakang masih berjalan, dan UI dalam kondisi sebagian ditarik. Harus mematikan seluruh aplikasi sebelum mulai bekerja lagi.
sumber
Jawaban:
Saat Anda mengalihkan orientasi, Android akan membuat Tampilan baru. Anda mungkin mengalami crash karena utas latar belakang Anda mencoba mengubah status pada yang lama. (Mungkin juga ada masalah karena utas latar belakang Anda tidak ada pada utas UI)
Saya sarankan membuat mHandler itu tidak stabil dan memperbaruinya ketika orientasi berubah.
sumber
Sunting: Insinyur Google tidak merekomendasikan pendekatan ini, seperti yang dijelaskan oleh Dianne Hackborn (alias hackbod ) dalam posting StackOverflow ini . Lihat posting blog ini untuk informasi lebih lanjut.
Anda harus menambahkan ini ke deklarasi aktivitas di manifes:
jadi sepertinya
Masalahnya adalah bahwa sistem menghancurkan aktivitas ketika perubahan dalam konfigurasi terjadi. Lihat Perubahan Konfigurasi .
Jadi dengan meletakkannya di file konfigurasi, hindari sistem untuk menghancurkan aktivitas Anda. Sebaliknya itu memanggil
onConfigurationChanged(Configuration)
metode.sumber
orientation
, ada banyak alasan untuk konfigurasi berubah:keyboardHidden
(Saya sudah mengedit jawaban wiki),uiMode
(Misalnya, masuk atau keluar dari mode mobil; mode malam berubah), dll. Sekarang saya bertanya-tanya apakah ini sebenarnya jawaban yang bagusSaya datang dengan solusi solid untuk masalah ini yang sesuai dengan 'Android Way'. Saya memiliki semua operasi jangka panjang saya menggunakan pola IntentService.
Artinya, kegiatan saya disiarkan maksud, yang IntentService melakukan pekerjaan, menyimpan data dalam DB dan kemudian menyiarkan lengket maksud. Bagian lengket penting, sedemikian sehingga bahkan jika Kegiatan dijeda selama selama waktu setelah pengguna memulai pekerjaan dan melewatkan siaran waktu nyata dari IntentService kita masih dapat menanggapi dan mengambil data dari Kegiatan panggilan.
ProgressDialog
s dapat bekerja dengan pola ini dengan cukup baikonSaveInstanceState()
.Pada dasarnya, Anda perlu menyimpan flag yang sedang Anda jalankan dialognya dalam bundel instance tersimpan. Jangan simpan objek dialog progres karena ini akan membocorkan seluruh aktivitas. Untuk memiliki pegangan yang persisten pada dialog progres, saya menyimpannya sebagai referensi yang lemah di objek aplikasi. Saat perubahan orientasi atau hal lain yang menyebabkan Aktivitas berhenti (panggilan telepon, pengguna menekan rumah, dll.) Dan kemudian melanjutkan, saya mengabaikan dialog lama dan membuat kembali dialog baru di Aktivitas yang baru dibuat.
Untuk dialog kemajuan yang tidak terbatas ini mudah. Untuk gaya bilah kemajuan, Anda harus meletakkan kemajuan yang diketahui terakhir di bundel dan informasi apa pun yang Anda gunakan secara lokal di aktivitas untuk melacak kemajuan. Pada memulihkan kemajuan, Anda akan menggunakan informasi ini untuk menelurkan kembali progress bar dalam keadaan yang sama seperti sebelumnya dan kemudian memperbarui berdasarkan keadaan saat ini.
Jadi untuk meringkas, menempatkan tugas yang sudah berjalan lama ke IntentService ditambah dengan penggunaan yang bijaksana
onSaveInstanceState()
memungkinkan Anda untuk secara efisien melacak dialog dan memulihkan kemudian di seluruh kegiatan siklus hidup Aktivitas. Bit kode aktivitas yang relevan ada di bawah ini. Anda juga akan memerlukan logika di BroadcastReceiver Anda untuk menangani maksud Sticky secara tepat, tetapi itu berada di luar cakupannya.sumber
Saya menemui masalah yang sama. Aktivitas saya perlu mem-parsing beberapa data dari URL dan lambat. Jadi saya membuat utas untuk melakukannya, lalu tampilkan dialog progres. Saya membiarkan utas memposting pesan kembali ke utas UI melalui
Handler
saat selesai. DiHandler.handleMessage
, saya mendapatkan objek data (siap sekarang) dari utas dan mengisinya ke UI. Jadi sangat mirip dengan contoh Anda.Setelah banyak trial and error sepertinya saya menemukan solusi. Setidaknya sekarang saya bisa memutar layar kapan saja, sebelum atau setelah utas selesai. Dalam semua tes, dialog ditutup dengan benar dan semua perilaku seperti yang diharapkan.
Apa yang saya lakukan ditunjukkan di bawah ini. Tujuannya adalah untuk mengisi model data saya (
mDataObject
) dan kemudian mengisinya ke UI. Seharusnya memungkinkan rotasi layar setiap saat tanpa kejutan.Itu yang berhasil untuk saya. Saya tidak tahu apakah ini metode "benar" seperti yang dirancang oleh Android - mereka mengklaim ini "hancurkan / buat kembali aktivitas selama rotasi layar" sebenarnya membuat segalanya lebih mudah, jadi saya kira itu tidak boleh terlalu rumit.
Beri tahu saya jika Anda melihat masalah dalam kode saya. Seperti yang dikatakan di atas, saya tidak benar-benar tahu apakah ada efek samping.
sumber
onRetainNonConfigurationInstance()
dangetLastNonConfigurationInstance()
membantu saya untuk menyelesaikan masalah saya. Jempolan!Masalah yang dirasakan asli adalah bahwa kode tidak akan selamat dari perubahan orientasi layar. Rupanya ini "diselesaikan" dengan meminta program menangani perubahan layar itu sendiri, alih-alih membiarkan kerangka UI melakukannya (melalui panggilan onDestroy)).
Saya akan menyampaikan bahwa jika masalah yang mendasarinya adalah bahwa program tidak akan bertahan diDestroy (), maka solusi yang diterima hanyalah solusi yang meninggalkan program dengan masalah serius lainnya dan kerentanan. Ingatlah bahwa kerangka kerja Android secara khusus menyatakan bahwa aktivitas Anda berisiko dihancurkan hampir setiap saat karena keadaan di luar kendali Anda. Oleh karena itu, aktivitas Anda harus dapat bertahan hidup diDestroy () dan onCreate () berikutnya dengan alasan apa pun, bukan hanya perubahan orientasi layar.
Jika Anda akan menerima penanganan sendiri perubahan orientasi layar untuk menyelesaikan masalah OP, Anda perlu memverifikasi bahwa penyebab lain dari onDestroy () tidak menghasilkan kesalahan yang sama. Apakah kamu bisa melakukan ini? Jika tidak, saya akan mempertanyakan apakah jawaban "diterima" benar-benar jawaban yang sangat baik.
sumber
Solusi saya adalah memperluas
ProgressDialog
kelas untuk mendapatkan kelas saya sendiriMyProgressDialog
.Saya mendefinisikan ulang
show()
dandismiss()
metode untuk mengunci orientasi sebelum menunjukkanDialog
dan membuka kembali ketikaDialog
diberhentikan. Jadi ketikaDialog
ditampilkan dan orientasi perangkat berubah, orientasi layar tetap sampaidismiss()
dipanggil, kemudian orientasi layar berubah sesuai dengan nilai sensor / orientasi perangkat.Ini kode saya:
sumber
Saya menghadapi masalah yang sama, dan saya datang dengan solusi yang tidak melibatkan menggunakan ProgressDialog dan saya mendapatkan hasil yang lebih cepat.
Apa yang saya lakukan adalah membuat tata letak yang memiliki ProgressBar di dalamnya.
Kemudian dalam metode onCreate lakukan hal berikut
Kemudian lakukan tugas panjang dalam utas, dan ketika itu selesai memiliki Runnable atur tampilan konten ke tata letak nyata yang ingin Anda gunakan untuk aktivitas ini.
Sebagai contoh:
Inilah yang saya lakukan, dan saya menemukan bahwa ini berjalan lebih cepat daripada menunjukkan ProgressDialog dan itu kurang mengganggu dan memiliki pandangan yang lebih baik menurut saya.
Namun, jika Anda ingin menggunakan ProgressDialog, maka jawaban ini bukan untuk Anda.
sumber
setContentView(R.layout.my_layout);
Tidak cukup; Anda perlu mengatur semua pendengar, mengatur ulang data, dll.Saya menemukan solusi untuk ini yang belum saya lihat di tempat lain. Anda dapat menggunakan objek aplikasi kustom yang tahu jika Anda memiliki tugas latar belakang, alih-alih mencoba melakukan ini dalam aktivitas yang dihancurkan dan diciptakan kembali saat perubahan orientasi. Saya membuat blog tentang ini di sini .
sumber
Application
biasanya digunakan untuk mempertahankan status aplikasi global. Saya tidak mengatakan itu tidak berhasil, tetapi tampaknya terlalu rumit. Dari doc "Biasanya tidak perlu untuk subkelas Aplikasi." Saya lebih suka jawaban sonxurxo.Saya akan berkontribusi dalam pendekatan saya untuk menangani masalah rotasi ini. Ini mungkin tidak relevan dengan OP karena dia tidak menggunakan
AsyncTask
, tetapi mungkin orang lain akan merasa berguna. Ini cukup sederhana tetapi tampaknya melakukan pekerjaan untuk saya:Saya memiliki aktivitas masuk dengan
AsyncTask
kelas bersarang yang disebutBackgroundLoginTask
.Dalam saya,
BackgroundLoginTask
saya tidak melakukan sesuatu yang luar biasa kecuali menambahkan cek nol padaProgressDialog
pemecatan panggilan :Ini untuk menangani kasus di mana tugas latar belakang selesai sementara
Activity
tidak terlihat dan, oleh karena itu, dialog progres telah diberhentikan olehonPause()
metode.Selanjutnya, di
Activity
kelas orang tua saya , saya membuat pegangan statis global untukAsyncTask
kelas saya dan sayaProgressDialog
(yangAsyncTask
, bersarang, dapat mengakses variabel-variabel ini):Ini melayani dua tujuan: Pertama, ini memungkinkan saya
Activity
untuk selalu mengaksesAsyncTask
objek bahkan dari aktivitas baru, setelah diputar. Kedua, memungkinkan sayaBackgroundLoginTask
untuk mengakses dan memberhentikanProgressDialog
bahkan setelah rotasi.Selanjutnya, saya menambahkan ini ke
onPause()
, menyebabkan dialog kemajuan menghilang ketika kitaActivity
meninggalkan latar depan (mencegah crash "paksa tutup" yang jelek):Akhirnya, saya memiliki yang berikut dalam
onResume()
metode saya :Ini memungkinkan
Dialog
untuk muncul kembali setelahActivity
diciptakan kembali.Inilah seluruh kelas:
Saya bukan pengembang Android berpengalaman, jadi jangan ragu untuk berkomentar.
sumber
Pindahkan tugas panjang ke kelas terpisah. Menerapkannya sebagai pola subjek-pengamat. Setiap kali kegiatan dibuat register dan sambil menutup batalkan registrasi dengan kelas tugas. Kelas tugas dapat menggunakan AsyncTask.
sumber
Caranya adalah dengan menampilkan / mengabaikan dialog dalam AsyncTask selama onPreExecute / onPostExecute seperti biasa, meskipun dalam hal perubahan orientasi buat / tampilkan contoh baru dari dialog dalam aktivitas dan berikan referensi untuk tugas tersebut.
sumber
Saya telah melakukannya seperti ini:
Anda juga dapat mencoba dan memberi tahu saya bahwa itu cocok untuk Anda atau tidak
sumber
Jika Anda membuat latar belakang
Service
yang melakukan semua pengangkatan berat (permintaan / respons tcp, unmarshalling),View
danActivity
dapat dihancurkan dan dibuat kembali tanpa membocorkan jendela atau kehilangan data. Ini memungkinkan perilaku yang disarankan Android, yaitu untuk menghancurkan Aktivitas pada setiap perubahan konfigurasi (mis. Untuk setiap perubahan orientasi).Ini sedikit lebih rumit, tetapi ini adalah cara terbaik untuk memohon permintaan server, data pra / pasca pemrosesan, dll.
Anda bahkan dapat menggunakan
Service
untuk mengantri setiap permintaan ke server, sehingga memudahkan dan efisien untuk menangani hal-hal itu.Panduan dev memiliki bab
Services
lengkap .sumber
Service
lebih banyak pekerjaan daripada sebuahAsyncTask
tetapi bisa menjadi pendekatan yang lebih baik dalam beberapa situasi. Belum tentu lebih baik, kan? Yang sedang berkata, saya tidak mengerti bagaimana ini memecahkan masalahProgressDialog
yang bocor dari utamaActivity
. Di mana Anda memulaiProgressDialog
? Di mana Anda menolaknya?Saya memiliki implementasi yang memungkinkan aktivitas dihancurkan pada perubahan orientasi layar, tetapi berhasil menghancurkan dialog dalam aktivitas yang dibuat ulang. Saya gunakan
...NonConfigurationInstance
untuk melampirkan tugas latar belakang ke aktivitas yang dibuat kembali. Kerangka kerja Android normal menangani menciptakan kembali dialog itu sendiri, tidak ada yang berubah di sana.Saya mensubklasifikasikan AsyncTask menambahkan bidang untuk aktivitas 'memiliki', dan metode untuk memperbarui pemilik ini.
Di kelas aktivitas saya, saya menambahkan bidang yang
backgroundTask
merujuk ke backgroundtask 'milik', dan saya memperbarui bidang ini menggunakanonRetainNonConfigurationInstance
dangetLastNonConfigurationInstance
.Saran untuk perbaikan lebih lanjut:
backgroundTask
referensi dalam aktivitas setelah tugas selesai untuk melepaskan memori atau sumber daya lain yang terkait dengannya.ownerActivity
referensi di backgroundtask sebelum aktivitas dimusnahkan seandainya tidak akan segera dibuat kembali.BackgroundTask
antarmuka dan / atau koleksi untuk memungkinkan berbagai jenis tugas dijalankan dari aktivitas kepemilikan yang sama.sumber
Jika Anda mempertahankan dua tata letak, semua utas UI harus dihentikan.
Jika Anda menggunakan AsynTask, maka Anda dapat dengan mudah memanggil
.cancel()
metode di dalamonDestroy()
metode aktivitas saat ini.Untuk AsyncTask, baca lebih lanjut di bagian "Membatalkan tugas" di sini .
Pembaruan: Menambahkan kondisi untuk memeriksa status, karena itu hanya dapat dibatalkan jika sedang dalam keadaan berjalan. Perhatikan juga bahwa AsyncTask hanya dapat dijalankan satu kali.
sumber
Mencoba untuk mengimplementasikan solusi jfelectron karena ini adalah " solusi yang kuat untuk masalah ini yang sesuai dengan 'Android Way' hal " tetapi butuh beberapa waktu untuk mencari dan mengumpulkan semua elemen yang disebutkan. Berakhir dengan ini sedikit berbeda, dan saya pikir lebih elegan, solusi diposting di sini secara keseluruhan.
Menggunakan IntentService yang dipecat dari suatu aktivitas untuk melakukan tugas jangka panjang pada utas terpisah. Layanan ini menjalankan kembali maksud Siaran yang lengket ke aktivitas yang memperbarui dialog. Aktivitas menggunakan showDialog (), onCreateDialog () dan onPrepareDialog () untuk menghilangkan kebutuhan untuk memiliki data persisten yang dilewatkan dalam objek aplikasi atau bundel SimpananInstanceState yang disimpan. Ini akan berfungsi tidak masalah bagaimana aplikasi Anda terganggu.
Kelas Kegiatan:
Kelas IntentService:
Entri file manifest:
sebelum bagian aplikasi:
di dalam bagian aplikasi
sumber
Ini adalah solusi yang saya usulkan:
void showProgressDialog()
metode dapat ditambahkan ke antarmuka pendengar fragmen-kegiatan untuk tujuan ini.sumber
Saya menghadapi situasi yang sama. Apa yang saya lakukan adalah hanya mendapatkan satu contoh untuk dialog progres saya di seluruh aplikasi.
Pertama, saya membuat kelas DialogSingleton untuk mendapatkan hanya satu instance (pola Singleton)
Seperti yang saya tunjukkan di kelas ini, saya memiliki dialog progres sebagai atribut. Setiap kali saya perlu menampilkan dialog progres, saya mendapatkan contoh unik dan membuat ProgressDialog baru.
Ketika saya selesai dengan tugas latar belakang, saya memanggil lagi contoh unik dan mengabaikan dialognya.
Saya menyimpan status tugas latar belakang di preferensi bersama saya. Ketika saya memutar layar, saya bertanya apakah saya memiliki tugas yang berjalan untuk aktivitas ini: (onCreate)
Ketika saya mulai menjalankan tugas latar belakang:
Ketika saya selesai menjalankan tugas latar belakang:
Saya harap ini membantu.
sumber
Ini adalah pertanyaan yang sangat lama yang muncul di sidebar karena alasan tertentu.
Jika tugas latar belakang hanya perlu bertahan saat aktivitas berada di latar depan, solusi "baru" adalah untuk menjadi tuan rumah utas latar belakang (atau, lebih disukai,
AsyncTask
) dalam fragmen yang dipertahankan , seperti yang dijelaskan dalam panduan pengembang ini dan banyak Tanya Jawab .Fragmen yang dipertahankan bertahan jika aktivitas dimusnahkan karena perubahan konfigurasi, tetapi tidak ketika aktivitas dimusnahkan di latar belakang atau tumpukan belakang. Oleh karena itu, tugas latar belakang harus tetap terputus jika
isChangingConfigurations()
salah dalamonPause()
.sumber
Saya lebih segar di android dan saya mencoba ini dan berhasil.
sumber
Saya sudah mencoba semuanya. Menghabiskan hari bereksperimen. Saya tidak ingin memblokir aktivitas agar tidak berputar. Skenario saya adalah:
Masalahnya adalah, ketika memutar layar, setiap solusi pada buku gagal. Bahkan dengan kelas AsyncTask, yang merupakan cara Android yang tepat untuk menghadapi situasi ini. Saat memutar layar, Konteks saat ini yang bekerja dengan thread awal, hilang, dan yang mengacaukan dialog yang ditampilkan. Masalahnya selalu Dialog, tidak peduli berapa banyak trik yang saya tambahkan ke kode (melewati konteks baru untuk menjalankan utas, mempertahankan status utas melalui rotasi, dll ...). Kompleksitas kode pada akhirnya selalu besar dan selalu ada sesuatu yang salah.
Satu-satunya solusi yang berhasil bagi saya adalah trik Activity / Dialog. Ini sederhana dan jenius dan itu semua bukti rotasi:
Alih-alih membuat Dialog dan meminta untuk menunjukkannya, buat Aktivitas yang telah diatur dalam manifes dengan android: theme = "@ android: style / Theme.Dialog". Jadi, itu hanya terlihat seperti dialog.
Ganti showDialog (DIALOG_ID) dengan startActivityForResult (yourActivityDialog, yourCode);
Gunakan onActivityResult dalam Aktivitas pemanggilan untuk mendapatkan hasil dari utas pelaksana (bahkan kesalahan) dan perbarui UI.
Di 'ActivityDialog' Anda, gunakan utas atau AsyncTask untuk menjalankan tugas yang panjang dan diRetainNonConfigurationInstance untuk menyimpan status "dialog" saat memutar layar.
Ini cepat dan berfungsi dengan baik. Saya masih menggunakan dialog untuk tugas-tugas lain dan AsyncTask untuk sesuatu yang tidak memerlukan dialog konstan di layar. Tetapi dengan skenario ini, saya selalu mencari pola Kegiatan / Dialog.
Dan, saya tidak mencobanya, tetapi bahkan mungkin untuk memblokir Kegiatan / Dialog agar tidak berputar, ketika utas berjalan, mempercepat, sementara memungkinkan Kegiatan pemanggilan berputar.
sumber
Intent
, yang lebih ketat daripada yangObject
diizinkan olehAsyncTask
Saat ini ada cara yang jauh lebih berbeda untuk menangani jenis masalah ini. Pendekatan khas adalah:
1. Pastikan data Anda dipisahkan dengan benar dari UI:
Apa pun yang merupakan proses latar belakang harus disimpan
Fragment
(set ini denganFragment.setRetainInstance()
. Ini menjadi 'penyimpanan data persisten' Anda di mana data apa pun yang ingin Anda pertahankan disimpan. Setelah acara perubahan orientasi, iniFragment
masih akan dapat diakses dengan aslinya nyatakan melaluiFragmentManager.findFragmentByTag()
panggilan (saat Anda membuatnya, Anda harus memberinya tag bukan ID karena tidak dilampirkan keView
).Lihat Menangani Runtime Changes panduan yang dikembangkan untuk informasi tentang melakukan ini dengan benar dan mengapa itu adalah pilihan terbaik.
2. Pastikan Anda berinteraksi dengan benar dan aman antara proses latar belakang dan UI Anda:
Anda harus membalikkan proses penautan Anda. Saat ini proses latar belakang Anda menempel pada
View
- sebagai gantinya AndaView
harus menempel sendiri ke proses latar belakang. Lebih masuk akal bukan? TheView
's tindakan tergantung pada proses latar belakang, sedangkan proses latar belakang tidak tergantung padaView
.Ini berarti mengubah link ke standarListener
antarmuka. Katakan proses Anda (apa pun kelasnya - apakah itu sebuahAsyncTask
,Runnable
atau apa pun) yang mendefinisikanOnProcessFinishedListener
, ketika proses itu dilakukan, Anda harus memanggil pendengar itu jika ada.Jawaban ini adalah deskripsi singkat yang bagus tentang bagaimana melakukan pendengar khusus.
3. Tautkan UI Anda ke dalam proses data setiap kali UI dibuat (termasuk perubahan orientasi):
Sekarang Anda harus khawatir tentang menghubungkan tugas latar belakang dengan apa pun
View
struktur Anda saat ini. Jika Anda menangani perubahan orientasi dengan benar (tidakconfigChanges
selalu disarankan orang hack), maka AndaDialog
akan dibuat ulang oleh sistem. Ini penting, artinya pada perubahan orientasi, semuaDialog
metode siklus hidup Anda dipanggil kembali. Jadi dalam salah satu metode ini (onCreateDialog
biasanya merupakan tempat yang baik), Anda dapat melakukan panggilan seperti berikut:Lihat siklus hidup Fragmen untuk menentukan di mana pengaturan pendengar paling cocok dalam implementasi pribadi Anda.
Ini adalah pendekatan umum untuk memberikan solusi yang kuat dan lengkap untuk masalah umum yang diajukan dalam pertanyaan ini. Mungkin ada beberapa bagian kecil yang hilang dalam jawaban ini tergantung pada skenario pribadi Anda, tetapi ini umumnya merupakan pendekatan yang paling tepat untuk menangani acara perubahan orientasi dengan tepat.
sumber
saya telah menemukan dan solusi yang lebih mudah untuk menangani utas ketika orientasi berubah. Anda bisa menyimpan referensi statis untuk aktivitas / fragmen Anda dan memverifikasi apakah nol sebelum bertindak pada ui. Saya sarankan menggunakan try catch juga:
sumber
Jika Anda kesulitan mendeteksi perubahan orientasi acara dialog INDEPENDEN DARI REFERENSI AKTIVITAS , metode ini bekerja dengan sangat baik. Saya menggunakan ini karena saya memiliki kelas dialog saya sendiri yang dapat ditampilkan di beberapa Aktivitas yang berbeda jadi saya tidak selalu tahu di mana Kegiatan itu ditampilkan. Dengan metode ini Anda tidak perlu mengubah AndroidManifest, khawatir tentang referensi Kegiatan, dan Anda tidak perlu dialog khusus (seperti yang saya miliki). Namun, Anda memerlukan tampilan konten khusus sehingga Anda dapat mendeteksi perubahan orientasi menggunakan tampilan tertentu. Inilah contoh saya:
Mendirikan
Implementasi 1 - Dialog
Implementasi 2 - AlertDialog.Builder
Implementasi 3 - ProgressDialog / AlertDialog
sumber
Ini adalah solusi saya ketika saya menghadapinya:
ProgressDialog
bukanFragment
anak kecil, jadi "ProgressDialogFragment
" kelas khusus saya dapat diperluasDialogFragment
untuk menjaga agar dialog tetap ditampilkan untuk perubahan konfigurasi.Ada 2 pendekatan untuk menyelesaikan ini:
Pendekatan pertama: Buat aktivitas yang memanfaatkan dialog untuk mempertahankan status selama konfigurasi perubahan dalam file manifes:
Pendekatan ini tidak disukai oleh Google.
Pendekatan kedua: pada metode aktivitas
onCreate()
, Anda perlu mempertahankannyaDialogFragment
dengan membangun kembaliProgressDialogFragment
lagi dengan judul & pesan sebagai berikut jikasavedInstanceState
tidak nol:sumber
Tampaknya terlalu 'cepat dan kotor' untuk menjadi kenyataan jadi tolong tunjukkan kekurangannya tetapi apa yang saya temukan berhasil ...
Dalam metode onPostExecute dari AsyncTask saya, saya hanya membungkus '.dismiss' untuk dialog progres di blok coba / tangkap (dengan tangkapan kosong) dan kemudian abaikan saja pengecualian yang dimunculkan. Tampaknya salah untuk dilakukan tetapi tampaknya tidak ada efek buruk (setidaknya untuk apa yang saya lakukan selanjutnya yaitu memulai aktivitas lain yang lulus sebagai hasil dari permintaan saya yang berjalan lama sebagai Ekstra)
sumber
Activity
referensi keDialog
. Ketika konfigurasi diubah, yang pertamaActivity
dihancurkan, yang berarti semua bidang diatur kenull
. Tetapi level rendahWindowManager
juga memiliki referensi keDialog
(karena belum diberhentikan). Yang baruActivity
mencoba untuk membuat yang baruDialog
(dalampreExecute()
) dan manajer jendela menimbulkan pengecualian fatal yang mencegah Anda melakukannya. Memang, jika itu terjadi, tidak akan ada cara untuk menghancurkan dengan bersihDialog
maka menjaga referensi ke awalActivity
. Apakah saya benar?Solusi paling sederhana dan paling fleksibel adalah dengan menggunakan AsyncTask dengan referensi statis ke ProgressBar . Ini memberikan solusi terenkapsulasi dan dengan demikian dapat digunakan kembali untuk masalah perubahan orientasi. Solusi ini telah membantu saya dengan baik untuk berbagai tugas asinkron termasuk unduhan internet, berkomunikasi dengan Layanan , dan pemindaian sistem file. Solusinya telah diuji dengan baik pada beberapa versi Android dan model telepon. Demo lengkap dapat ditemukan di sini dengan minat khusus pada DownloadFile.java
Saya menyajikan berikut ini sebagai contoh konsep
Penggunaan dalam Aktivitas Android sederhana
sumber
Saat Anda mengubah orientasi, Android membunuh aktivitas itu dan membuat aktivitas baru. Saya menyarankan untuk menggunakan retrofit dengan Rx java. yang menangani crash secara otomatis.
Gunakan metode ini saat retrofit memanggil.
.subscribeOn (Schedulers.io ()) .observeOn (AndroidSchedulers.mainThread ())
sumber