Saya telah menyelidiki masalah ini selama berbulan-bulan sekarang, muncul dengan solusi yang berbeda untuk itu, yang saya tidak senang karena mereka semua peretasan besar. Saya masih tidak percaya bahwa kelas yang cacat dalam desain membuatnya masuk ke kerangka kerja dan tidak ada yang membicarakannya, jadi saya kira saya pasti kehilangan sesuatu.
Masalahnya dengan AsyncTask
. Menurut dokumentasi itu
"memungkinkan untuk melakukan operasi latar belakang dan menerbitkan hasil pada utas UI tanpa harus memanipulasi utas dan / atau penangan."
Contoh kemudian terus menunjukkan bagaimana beberapa showDialog()
metode teladan dipanggil onPostExecute()
. Ini, bagaimanapun, tampaknya sepenuhnya dibuat - buat untuk saya, karena menunjukkan dialog selalu membutuhkan referensi ke yang valid Context
, dan AsyncTask tidak boleh memiliki referensi yang kuat untuk objek konteks .
Alasannya jelas: bagaimana jika aktivitas itu hancur yang memicu tugas? Ini dapat terjadi setiap saat, misalnya karena Anda membalik layar. Jika tugas akan menyimpan referensi ke konteks yang membuatnya, Anda tidak hanya berpegang pada objek konteks yang tidak berguna (jendela akan hancur dan interaksi UI apa pun akan gagal dengan pengecualian!), Anda bahkan berisiko membuat kebocoran memori.
Kecuali jika logika saya cacat di sini, ini berarti: onPostExecute()
sama sekali tidak berguna, karena apa gunanya metode ini berjalan di utas UI jika Anda tidak memiliki akses ke konteks apa pun? Anda tidak dapat melakukan sesuatu yang berarti di sini.
Satu solusi adalah dengan tidak mengirimkan instance konteks ke AsyncTask, tetapi sebuah Handler
instance. Itu bekerja: karena Handler secara longgar mengikat konteks dan tugas, Anda dapat bertukar pesan di antara mereka tanpa risiko kebocoran (kan?). Tetapi itu berarti bahwa premis AsyncTask, yaitu bahwa Anda tidak perlu repot dengan penangan, salah. Sepertinya juga menyalahgunakan Handler, karena Anda mengirim dan menerima pesan pada utas yang sama (Anda membuatnya pada utas UI dan mengirimkannya dalam onPostExecute () yang juga dijalankan pada utas UI).
Untuk melengkapi semuanya, bahkan dengan penyelesaian itu, Anda masih memiliki masalah bahwa ketika konteksnya dihancurkan, Anda tidak memiliki catatan tugas yang dipecatnya. Itu berarti bahwa Anda harus memulai kembali tugas apa pun ketika menciptakan kembali konteks, misalnya setelah perubahan orientasi layar. Ini lambat dan boros.
Solusi saya untuk ini (seperti yang diterapkan di perpustakaan Droid-Fu ) adalah mempertahankan pemetaan WeakReference
s dari nama komponen ke instance mereka saat ini pada objek aplikasi yang unik. Setiap kali AsyncTask dimulai, ia merekam konteks panggilan di peta itu, dan pada setiap panggilan balik, ia akan mengambil instance konteks saat ini dari pemetaan itu. Ini memastikan bahwa Anda tidak akan pernah merujuk contoh konteks basi dan Anda selalu memiliki akses ke konteks yang valid dalam panggilan balik sehingga Anda dapat melakukan pekerjaan UI yang bermakna di sana. Itu juga tidak bocor, karena referensi lemah dan dihapus ketika tidak ada contoh komponen yang diberikan ada lagi.
Namun, ini merupakan solusi yang kompleks dan mengharuskan untuk mensubkelas beberapa kelas perpustakaan Droid-Fu, menjadikannya pendekatan yang cukup mengganggu.
Sekarang saya hanya ingin tahu: Apakah saya hanya melewatkan sesuatu secara besar-besaran atau apakah AsyncTask sepenuhnya cacat? Bagaimana pengalaman Anda bekerja dengannya? Bagaimana Anda memecahkan masalah ini?
Terima kasih atas masukan Anda.