AsyncTask
adalah hal yang hebat untuk menjalankan tugas kompleks di utas lainnya.
Tetapi ketika ada perubahan orientasi atau perubahan konfigurasi lain saat AsyncTask
masih berjalan, saat Activity
ini dihancurkan dan restart. Dan ketika instance AsyncTask
terhubung ke aktivitas itu, ia gagal dan menyebabkan jendela pesan "tutup paksa".
Jadi, saya mencari semacam "praktik terbaik" untuk menghindari kesalahan ini dan mencegah kegagalan AsyncTask.
Apa yang saya lihat sejauh ini adalah:
- Nonaktifkan perubahan orientasi. (Pasti bukan cara Anda harus menangani ini.)
- Membiarkan tugas bertahan dan memperbaruinya dengan instance aktivitas baru via
onRetainNonConfigurationInstance
- Membatalkan tugas saat
Activity
dimusnahkan dan memulai kembali saat tugasActivity
dibuat kembali. - Mengikat tugas ke kelas aplikasi alih-alih instance aktivitas.
- Beberapa metode yang digunakan dalam proyek "rak" (via onRestoreInstanceState)
Beberapa contoh kode:
Android AsyncTasks selama rotasi layar, Bagian I dan Bagian II
Dapatkah Anda membantu saya menemukan pendekatan terbaik yang memecahkan masalah terbaik dan juga mudah diimplementasikan? Kode itu sendiri juga penting karena saya tidak tahu bagaimana menyelesaikannya dengan benar.
Jawaban:
Apakah TIDAK menggunakan
android:configChanges
untuk mengatasi masalah ini. Ini praktik yang sangat buruk.Apakah TIDAK menggunakan
Activity#onRetainNonConfigurationInstance()
baik. Ini kurang modular dan tidak cocok untukFragment
aplikasi berbasis.Anda dapat membaca artikel saya yang menjelaskan cara menangani perubahan konfigurasi menggunakan retained
Fragment
s. Ini memecahkan masalah mempertahankanAsyncTask
perubahan rotasi yang baik. Pada dasarnya Anda perlu untuk menjadi tuan rumah AndaAsyncTask
di dalamFragment
, panggilansetRetainInstance(true)
padaFragment
, dan melaporkanAsyncTask
's kemajuan / hasil kembali ke ituActivity
melalui dipertahankanFragment
.sumber
TabActivity
. Sejujurnya, saya tidak yakin mengapa kita berbicara tentang ini ... semua orang setuju bahwaFragment
ini adalah cara untuk pergi. :)Saya biasanya menyelesaikan ini dengan meminta AsyncTasks saya menyalakan Intents broadcast di .onPostExecute (), jadi mereka tidak mengubah Kegiatan yang memulai secara langsung. Kegiatan mendengarkan siaran ini dengan BroadcastReceivers dinamis dan bertindak sesuai.
Dengan cara ini, AsyncTasks tidak perlu peduli dengan instance Activity spesifik yang menangani hasilnya. Mereka hanya "berteriak" ketika mereka selesai, dan jika suatu Kegiatan ada di sekitar waktu itu (aktif dan fokus / dalam keadaan dilanjutkan) yang tertarik dengan hasil tugas, maka itu akan ditangani.
Ini melibatkan sedikit lebih banyak overhead, karena runtime perlu menangani siaran, tetapi saya biasanya tidak keberatan. Saya pikir menggunakan LocalBroadcastManager daripada lebar sistem default yang mempercepat semuanya.
sumber
Berikut adalah contoh lain dari AsyncTask yang menggunakan a
Fragment
untuk menangani perubahan konfigurasi runtime (seperti ketika pengguna memutar layar)setRetainInstance(true)
. Bilah kemajuan yang ditentukan (diperbarui secara berkala) juga ditunjukkan.Contohnya sebagian didasarkan pada dokumen resmi, Mempertahankan Objek Selama Perubahan Konfigurasi .
Dalam contoh ini pekerjaan yang membutuhkan utas latar belakang adalah hanya memuat gambar dari internet ke UI.
Alex Lockwood tampaknya benar bahwa ketika menangani perubahan konfigurasi runtime dengan AsyncTasks menggunakan "Retained Fragment" adalah praktik terbaik.
onRetainNonConfigurationInstance()
akan ditinggalkan di Lint, di Android Studio. Dokumen resmi memperingatkan kami untuk tidak menggunakanandroid:configChanges
, dari Menangani Konfigurasi, Ubah Diri , ...Lalu ada masalah apakah seseorang harus menggunakan AsyncTask sama sekali untuk utas latar belakang.
The referensi resmi untuk AsyncTask memperingatkan ...
Atau orang dapat menggunakan layanan, loader (menggunakan CursorLoader atau AsyncTaskLoader), atau penyedia konten untuk melakukan operasi asinkron.
Saya memecah sisa posting menjadi:
Prosedur
Mulailah dengan AsyncTask dasar sebagai kelas dalam dari suatu kegiatan (tidak perlu menjadi kelas dalam tetapi mungkin akan nyaman untuk dilakukan). Pada tahap ini AsyncTask tidak menangani perubahan konfigurasi runtime.
Tambahkan kelas bersarang RetainedFragment yang memperluas kelas Fragement dan tidak memiliki UI sendiri. Tambahkan setRetainInstance (true) ke acara onCreate dari fragmen ini. Berikan prosedur untuk mengatur dan mendapatkan data Anda.
Di onCreate kelas aktivitas terluar () menangani RetainedFragment: Referensi itu jika sudah ada (dalam hal aktivitas me-restart); buat dan tambahkan jika tidak ada; Kemudian, jika sudah ada, dapatkan data dari RetainedFragment dan atur UI Anda dengan data itu.
Memulai AsyncTask dari UI
Tambahkan dan beri kode bilah kemajuan yang ditentukan:
Semua kode untuk prosedur di atas
Tata Letak Aktivitas.
Aktivitas dengan: subclassed AsyncTask inner class; kelas dalam RetainedFragment subclass yang menangani perubahan konfigurasi runtime (misalnya ketika pengguna memutar layar); dan pembaruan progress bar yang ditentukan secara berkala. ...
Dalam contoh ini fungsi perpustakaan (direferensikan di atas dengan awalan paket eksplisit com.example.standardapplibrary.android.Network) yang melakukan pekerjaan nyata ...
Tambahkan izin apa pun yang diperlukan tugas latar belakang Anda ke AndroidManifest.xml ...
Tambahkan aktivitas Anda ke AndroidManifest.xml ...
sumber
Baru-baru ini, saya menemukan solusi yang bagus di sini . Ini didasarkan pada penyimpanan objek tugas melalui RetainConfiguration. Menurut saya, solusinya sangat elegan dan bagi saya, saya sudah mulai menggunakannya. Anda hanya perlu membuat sarang dari asynctask Anda dari basetask dan itu saja.
sumber
Berdasarkan jawaban @Alex Lockwood dan pada @William & @quickdraw mcgraw jawaban pada posting ini: Cara menangani pesan Handler ketika aktivitas / fragmen dijeda , saya menulis solusi generik.
Dengan cara ini rotasi ditangani, dan jika aktivitas berjalan ke latar belakang selama pelaksanaan tugas async, aktivitas akan menerima panggilan balik (onPreExecute, onProgressUpdate, onPostExecute & onCancelled) setelah dilanjutkan, sehingga tidak ada IllegalStateException yang akan dilemparkan (lihat Cara menangani Handler pesan saat aktivitas / fragmen dijeda ).
Akan lebih baik memiliki hal yang sama tetapi dengan tipe argumen umum, seperti AsyncTask (misalnya: AsyncTaskFragment <Params, Progress, Result>), tetapi saya tidak berhasil melakukannya dengan cepat dan tidak punya waktu saat ini. Jika ada yang ingin melakukan perbaikan, silakan saja!
Kode:
Anda membutuhkan PauseHandler:
Penggunaan sampel:
sumber
Anda dapat menggunakan Loader untuk ini. Periksa Doc di sini
sumber
Bagi mereka yang ingin menghindari Fragmen, Anda dapat mempertahankan AsyncTask berjalan pada perubahan orientasi menggunakan onRetainCustomNonConfigurationInstance () dan beberapa kabel.
(Perhatikan bahwa metode ini adalah alternatif untuk onRetainNonConfigurationInstance () ) yang sudah usang () ).
Sepertinya solusi ini tidak sering disebutkan. Saya menulis contoh menjalankan sederhana untuk menggambarkan.
Bersulang!
sumber
Saya telah menerapkan perpustakaan yang dapat memecahkan masalah dengan aktivitas jeda dan rekreasi saat tugas Anda sedang dijalankan.
Anda harus menerapkan
AsmykPleaseWaitTask
danAsmykBasicPleaseWaitActivity
. Aktivitas aktivitas dan latar belakang Anda akan berfungsi dengan baik bahkan ketika Anda akan memutar layar dan beralih di antara aplikasisumber
WORKAROUND CEPAT (tidak direkomendasikan)
Menghindari Aktivitas untuk dihancurkan dan membuat sendiri berarti mendeklarasikan aktivitas Anda dalam file manifes: android: configChanges = "orientasi | keyboardHidden | screenSize
Seperti yang disebutkan dalam dokumen
sumber