Uzun süren işlemler için Android AsyncTask


91

Burada bulunan AsyncTask belgelerinden alıntı yapmak şöyle diyor:

AsyncTasks ideal olarak kısa işlemler için kullanılmalıdır (en fazla birkaç saniye.) İş parçacıkları uzun süre çalışır durumda tutmanız gerekiyorsa, java.util.concurrent pacakge tarafından sağlanan çeşitli API'leri kullanmanız önemle tavsiye edilir. Yürütücü, ThreadPoolExecutor ve FutureTask.

Şimdi sorum ortaya çıkıyor: neden? doInBackground()UI iş parçacığı kapalı fonksiyon çalışır ne zarar yüzden burada uzun süreli işlem alarak var mı?


2
Bir uygulamayı (asyncTask kullanan) gerçek bir cihaza dağıtırken karşılaştığım sorun doInBackground, bir ilerleme çubuğu kullanılmadığında uzun süre çalışan işlevin ekranı dondurmasıydı.
venkatKA

2
Bir AsyncTask, başlatıldığı Aktiviteye bağlı olduğundan, Aktivite öldürülürse, AsyncTask örneğiniz de öldürülebilir.
IgorGanapolsky

Bir Hizmet içinde AsyncTask oluşturursam ne olur? Bu sorunu çözmez mi?
eddy

1
Uzun işlemi arka planda çalıştırmak için IntentService, Mükemmel çözüm kullanın.
Keyur Thumar

Yanıtlar:


121

Bu çok güzel bir soru, bir Android Programcısı olarak sorunu tam olarak anlamak zaman alıyor. Indeed AsyncTask'ın birbiriyle ilişkili iki ana sorunu vardır:

  • Aktivite yaşam döngüsüne zayıf bir şekilde bağlılar
  • Çok kolay bellek sızıntıları yaratırlar.

İçinde RoboSpice (Motivasyonları uygulamasında Google Play'de sunulan ) detaylı olarak bu soruya cevap. AsyncTasks, Loaders, özellikleri ve dezavantajları hakkında derinlemesine bir görünüm sunacak ve ayrıca ağ talepleri için alternatif bir çözüm sunacaktır: RoboSpice. Ağ istekleri Android'de yaygın bir gereksinimdir ve doğası gereği uzun süren işlemlerdir. İşte uygulamadan bir alıntı:

AsyncTask ve Activity yaşam döngüsü

AsyncTasks, Etkinlik örneklerinin yaşam döngüsünü izlemez. Bir Activity içinde bir AsyncTask başlatırsanız ve cihazı döndürürseniz, Aktivite yok edilecek ve yeni bir örnek oluşturulacaktır. Ancak AsyncTask ölmeyecek. Tamamlanana kadar yaşamaya devam edecek.

Ve tamamlandığında, AsyncTask yeni Aktivitenin kullanıcı arayüzünü güncellemez. Aslında, artık görüntülenmeyen etkinliğin önceki örneğini günceller. Bu, java.lang.IllegalArgumentException türünde bir İstisnaya yol açabilir: Örneğin, Activity içinde bir görünümü almak için findViewById kullanıyorsanız, pencere yöneticisine görünüm eklenmez.

Bellek sızıntısı sorunu

AsyncTasks'i Etkinliklerinizin iç sınıfları olarak oluşturmak çok uygundur. AsyncTask'ın, görev tamamlandığında veya devam ederken Aktivite görünümlerini manipüle etmesi gerekeceğinden, Aktivitenin bir iç sınıfını kullanmak uygun görünmektedir: iç sınıflar, dış sınıfın herhangi bir alanına doğrudan erişebilir.

Bununla birlikte, bu, iç sınıfın, dış sınıf örneğinde görünmez bir referans tutacağı anlamına gelir: Activity.

Uzun vadede, bu bir bellek sızıntısı yaratır: AsyncTask uzun sürerse, etkinliği "canlı" tutarken, Android artık görüntülenemediği için ondan kurtulmak ister. Etkinlik çöp olarak toplanamaz ve bu, Android'in cihazdaki kaynakları korumak için merkezi bir mekanizmadır.


Uzun süre çalışan işlemler için AsyncTasks kullanmak gerçekten çok çok kötü bir fikir. Yine de, 1 veya 2 saniye sonra bir Görünümü güncelleme gibi kısa ömürlü olanlar için iyidirler.

RoboSpice Motivations uygulamasını indirmenizi tavsiye ediyorum , bu gerçekten bunu derinlemesine açıklıyor ve bazı arka plan işlemlerini yapmanın farklı yollarının örneklerini ve gösterilerini sağlıyor.


@Snicolas Merhaba. NFC etiketindeki verileri taradığı ve sunucuya gönderdiği bir uygulamam var. İyi sinyal alanlarında iyi çalışır, ancak sinyalin olmadığı yerlerde web aramayı sürdüren AsyncTask çalışır. Örneğin, ilerleme iletişim kutusu dakikalarca çalışır ve sonra kaybolduğunda ekran kararır ve yanıt vermez. My AsyncTask bir iç sınıftır. X saniye sonra görevi iptal etmek için bir İşleyici yazıyorum. Uygulama, taramadan saatler sonra sunucuya eski verileri gönderiyor gibi görünüyor. Bunun nedeni AsyncTask'in bitmemesi ve belki saatler sonra tamamlanması olabilir mi? Herhangi bir görüşe minnettar olurum. teşekkürler
turtleboy

Ne olacağını görmek için izleyin. Ama evet, bu oldukça mümkün! Asenkron görevinizi iyi bir şekilde tasarlarsanız, onu oldukça düzgün bir şekilde iptal edebilirsiniz, RS veya bir hizmete geçmek istemiyorsanız bu iyi bir başlangıç ​​noktası olur ...
Snicolas

@Snicolas Cevap için teşekkürler. Dün SO'da sorunumu özetleyen ve AsyncTask'ı 8 saniye sonra durdurmayı denemek için yazdığım işleyici kodunu gösteren bir gönderi yaptım. Vaktin olursa bir göz atabilir misin? İşleyiciden AsyncTask.cancel'i (true) çağırmak görevi doğru şekilde iptal eder mi? DoInBackgroud'umdaki iscancelled () değerini periyodik olarak kontrol etmem gerektiğini biliyorum, ancak yalnızca tek satırlık bir web araması HttpPost yaptığım ve kullanıcı arayüzünde güncellemeleri yayınlamadığım için kendi koşullarım için geçerli olduğunu düşünmüyorum. mesela bir IntentService bir HttPost yapmak mümkündür
turtleboy


RoboSpice'i denemelisiniz (github'da). ;)
Snicolas

38

neden ?

Çünkü AsyncTaskvarsayılan olarak sizin oluşturmadığınız bir iş parçacığı havuzunu kullanır . Bu havuzun gereksinimlerinin ne olduğunu bilmediğiniz için, kendi oluşturmadığınız bir havuzdaki kaynakları asla bağlamayın. Ve burada olduğu gibi, o havuzun dokümantasyonu yapmamanızı söylüyorsa, oluşturmadığınız bir havuzdaki kaynakları asla bağlamayın.

Özellikle, Android 3.2'den başlayarak, AsyncTaskvarsayılan olarak kullanılan iş parçacığı havuzunun ( android:targetSdkVersion13 veya daha yüksek bir değere ayarlanmış uygulamalar için ) içinde yalnızca bir iş parçacığı vardır - bu iş parçacığını süresiz olarak bağlarsanız, diğer görevlerinizden hiçbiri çalışmayacaktır.


Bu açıklama için teşekkürler .. Uzun süreli işlemler için AsyncTasks kullanımıyla ilgili gerçekten hatalı bir şey bulamadım (ancak bunları genellikle Hizmetler'e kendim veriyorum), ancak bu ThreadPool'u bağlama konusundaki argümanınız (bunun için gerçekten yapabilirsiniz boyutu hakkında hiçbir varsayımda bulunmayın) yerinde görünüyor. Anup'ın bir hizmet kullanımıyla ilgili gönderisine ek olarak: Bu hizmetin kendisi de görevi arka planda çalıştırmalı ve kendi ana iş parçacığını engellememelidir. Bir seçenek, bir IntentService olabilir veya daha karmaşık eşzamanlılık gereksinimleri için kendi çoklu okuma stratejinizi uygulayın.
33'te baske

Bir Hizmet içinde AsyncTask'ı başlatsam bile aynı mı? Demek istediğim, uzun süredir devam eden operasyon hala sorun olur mu?
Girdap

1
@eddy: Evet, iş parçacığı havuzunun doğasını değiştirmez. A için Service, sadece a Threadveya a kullanın ThreadPoolExecutor.
CommonsWare

Teşekkürler @CommonsWare sadece son soru, TimerTasks AsyncTasks ile aynı dezavantajları paylaşıyor mu? yoksa tamamen farklı bir şey mi?
Girdap

1
@eddy: TimerTaskAndroid değil, standart Java'dandır. (ismine rağmen, standart Java'nın bir parçası olan) TimerTasklehine büyük ölçüde terk edilmiştir ScheduledExecutorService. İkisi de Android'e bağlı değildir ve bu nedenle, bu şeylerin arka planda çalışmasını bekliyorsanız yine de bir servise ihtiyacınız var. Ve, Android'den gerçekten düşünmelisiniz AlarmManager, böylece sadece saatin tik takını izleyerek etrafta asılı bir hizmete ihtiyacınız yoktur.
CommonsWare

4

Aysnc görevi, yine de uygulamalarınızın GUI'si ile kullanılması amaçlanan, ancak UI iş parçacığının kaynak ağırlıklı görevlerini korurken kullanılan özel iş parçacıklarıdır. Bu nedenle, listeleri güncelleme, görünümlerinizi değiştirme vb. Şeyler bazı getirme işlemleri yapmanızı veya güncelleme işlemlerini yapmanızı gerektirdiğinde, bu işlemleri UI iş parçacığından uzak tutabilmek için eşzamansız görevler kullanmalısınız, ancak bu işlemlerin hala bir şekilde UI'ye bağlı olduğunu unutmayın. .

UI güncellemesi gerektirmeyen daha uzun süre çalışan görevler için, bunun yerine hizmetleri kullanabilirsiniz çünkü bunlar bir UI olmadan bile yaşayabilirler.

Bu nedenle, kısa görevler için eşzamansız görevler kullanın çünkü üreme etkinliğiniz öldükten sonra işletim sistemi tarafından öldürülürler (genellikle işlemin ortasında ölmezler ancak görevini tamamlarlar). Uzun ve tekrar eden görevler için bunun yerine hizmetleri kullanın.

Daha fazla bilgi için Konuları görün:

AsyncTask birkaç saniyeden daha uzun bir süre mi?

ve

AsyncTask, etkinlik yok olsa bile durmaz


1

AsyncTask ile ilgili sorun, etkinliğin statik olmayan iç sınıfı olarak tanımlanırsa, etkinliğe bir referansa sahip olmasıdır. Zaman uyumsuz görev kapsayıcısının etkinliğinin bittiği, ancak AsyncTask'taki arka plan çalışmasının devam ettiği senaryoda, etkinlik nesnesi, kendisine bir başvuru olduğu için çöp toplanmayacaktır, bu da bellek sızıntısına neden olur.

Bunu düzeltmenin çözümü, zaman uyumsuz görevi statik iç etkinlik sınıfı olarak tanımlamak ve bağlama göre zayıf başvuru kullanmaktır.

Ancak yine de, basit ve hızlı arka plan görevleri için kullanmak iyi bir fikirdir. Temiz kod ile uygulama geliştirmek için karmaşık arka plan görevlerini çalıştırmak ve kullanıcı arayüzünü ondan elde edilen sonuçlarla güncellemek için RxJava kullanmak daha iyidir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.