Bu problemi aylardır araştırdım, hepsi büyük bir hack olduğu için memnun olmadığım farklı çözümler buldum. Tasarımda kusurlu bir sınıfın onu çerçeveye dönüştürdüğüne hala inanamıyorum ve hiç kimse bunun hakkında konuşmuyor, bu yüzden sanırım sadece bir şey eksik olmalıyım.
Sorun şu AsyncTask
. Belgelere göre
"iş parçacıklarını ve / veya işleyicileri değiştirmek zorunda kalmadan arka plan işlemleri gerçekleştirmeye ve sonuçları UI iş parçacığında yayınlamaya izin verir."
Örnek daha sonra örnek bir showDialog()
yöntemin nasıl çağrıldığını göstermeye devam eder onPostExecute()
. Bununla birlikte, bu benim için tamamen çelişkili görünmektedir , çünkü bir diyalogun gösterilmesi her zaman geçerli bir referansa ihtiyaç duyar Context
ve AsyncTask hiçbir zaman bir bağlam nesnesine güçlü bir referans içermemelidir .
Sebep açıktır: ya aktiviteyi tahrip eden görevi tahrip ederse? Bu her zaman olabilir, örneğin ekranı çevirdiğiniz için. Görev, onu oluşturan bağlama referans verirse, yalnızca işe yaramaz bir bağlam nesnesine tutunmazsınız (pencere yok edilir ve herhangi bir UI etkileşimi bir istisna dışında başarısız olur!) bellek sızıntısı.
Mantığım burada kusurlu olmadıkça, bu onPostExecute()
şu anlama gelir: tamamen işe yaramaz, çünkü herhangi bir bağlama erişiminiz yoksa bu yöntemin UI iş parçacığında çalışması ne kadar iyi? Burada anlamlı bir şey yapamazsınız.
Geçici çözümlerden biri bağlam örneklerini bir AsyncTask'e değil bir Handler
örneğe geçirmektir . Bu işe yarar: Bir İşleyici bağlamı ve görevi gevşek bir şekilde bağladığından, sızıntı riski olmadan aralarında mesaj alışverişi yapabilirsiniz (değil mi?). Ancak bu, AsyncTask'in öncülünün, yani işleyicileri rahatsız etmenize gerek olmadığı anlamına gelir. Aynı iş parçacığında mesaj gönderip aldığınız için de Handler'ı kötüye kullanmak gibi görünüyor (bunu UI iş parçacığında oluşturup UI iş parçacığında da yürütülen onPostExecute () içinde gönderirsiniz).
Her şeyden önemlisi, bu geçici çözümde bile, bağlam yok edildiğinde, tetiklediği görevlerin hiçbir kaydına sahip olmamanız sorununa sahipsiniz . Bu, içeriği yeniden oluştururken, örneğin bir ekran yönlendirme değişikliğinden sonra, tüm görevleri yeniden başlatmanız gerektiği anlamına gelir. Bu yavaş ve savurgan.
Buna benim çözümüm ( Droid-Fu kütüphanesinde uygulandığı gibi ), WeakReference
bileşen adlarından benzersiz uygulama nesnesindeki mevcut örneklerine bir eşleme sağlamaktır . Bir AsyncTask başlatıldığında, çağıran bağlamı bu haritaya kaydeder ve her geri çağrıldığında geçerli bağlam örneğini bu eşlemeden alır. Eğer eski bir bağlam örneğini başvuru asla Bu olmasını sağlar ve orada anlamlı UI işi yapabilir böylece her zaman geri çağrıları geçerli bir içeriğe erişebilir. Ayrıca sızıntı yapmaz, çünkü referanslar zayıftır ve artık belirli bir bileşenin örneği olmadığında temizlenir.
Yine de, karmaşık bir çözümdür ve Droid-Fu kütüphane sınıflarının bazılarını alt sınıflara ayırmayı gerektirir, bu da bunu oldukça müdahaleci bir yaklaşım haline getirir.
Şimdi sadece bilmek istiyorum: Bir şeyi büyük ölçüde özlüyor muyum yoksa AsyncTask gerçekten tamamen kusurlu mu? Deneyimleriniz onunla nasıl çalışıyor? Bu sorunu nasıl çözdün?
Girdiniz için teşekkürler.