Timertask veya İşleyici


104

Diyelim ki her 10 saniyede bir bazı eylemler gerçekleştirmek istiyorum ve görünümü mutlaka güncellemesine gerek yok.

Soru şu: zamanlayıcıyı aşağıdaki gibi zamanlayıcıyla kullanmak daha mı iyi (yani daha verimli ve etkili):

final Handler handler = new Handler();

TimerTask timertask = new TimerTask() {
    @Override
    public void run() {
        handler.post(new Runnable() {
            public void run() {
               <some task>
            }
        });
    }
};
timer = new Timer();
timer.schedule(timertask, 0, 15000);
}

veya sadece sonradan gecikmiş bir işleyici

final Handler handler = new Handler(); 
final Runnable r = new Runnable()
{
    public void run() 
    {
        <some task>
    }
};
handler.postDelayed(r, 15000);

Ayrıca hangi yaklaşımı ne zaman kullanacağınızı ve neden birinin diğerinden daha verimli olduğunu (eğer gerçekten öyleyse) açıklarsanız minnettar olurum.


2
TimerTasks'in düzensiz davranışları hakkında birçok yazı okudum. Benim tavsiyem onlardan uzak durmak ve eylemci / gecikme sonrası yaklaşımını kullanmak olacaktır.
Sound Conception

1
Handler-postDelay yöntemini tercih ederim - daha fazla kontrole sahipsiniz ve bunu içeriden planlarsınız
mihail


TimerTask bir arka plan görevidir, bu nedenle kullanıcı arayüzünü güncelleyemezsiniz. Sadece söylüyorum ...
Yousha Aleayoub

1
benim için çalıştı .. teşekkürler
jyotsna

Yanıtlar:


97

Handlerdaha iyidir TimerTask.

Java TimerTaskve Android Handler, arka plan iş parçacıklarında geciken ve tekrarlanan görevleri zamanlamanıza olanak tanır. Ancak, literatür ezici kullanılmasını önerir Handlerüzerinde TimerTask(bkz Android'de burada , burada , burada , burada , burada ve burada ).

TimerTask ile ilgili bildirilen sorunlardan bazıları şunlardır:

  • UI iş parçacığı güncellenemiyor
  • Bellek sızıntıları
  • Güvenilmez (her zaman işe yaramaz)
  • Uzun süre çalışan görevler, bir sonraki planlanmış olayı engelleyebilir

Misal

Gördüğüm tüm Android örnekleri için en iyi kaynak Codepath'de . İşte Handlertekrar eden bir görev için oradan bir örnek.

// Create the Handler object (on the main thread by default)
Handler handler = new Handler();
// Define the code block to be executed
private Runnable runnableCode = new Runnable() {
    @Override
    public void run() {
      // Do something here on the main thread
      Log.d("Handlers", "Called on main thread");
      // Repeat this the same runnable code block again another 2 seconds
      handler.postDelayed(runnableCode, 2000);
    }
};
// Start the initial runnable task by posting through the handler
handler.post(runnableCode);

İlişkili


6
@Reek Hayır, GC ilgilenmeli. Ancak gecikmiş yürütme için gönderilen çalıştırılabilir duruma dikkat etmeniz gerekir. Yukarıdaki örnekte kullanılan runnable, bir iç sınıf örneğidir, bu nedenle içeren sınıfa (bir etkinlik olabilir) örtük bir referans içerir. Runnable, bağlam geçersiz olduktan sonra olabilecek ve kapsayıcı sınıf örneğini sızdırabilecek bir sonraki yürütme zamanına kadar işleyicinin ilişkili döngüleyicinin ileti kuyruğunda kalacaktır. Bu tür referansları mHandler.removeCallbacks(runnableCode)uygun zamanda kullanarak silebilirsiniz (örneğin onStop()bir faaliyet için).
bitbybit

7
Referansları sunmanın en iyi yolu !!! (buraya, buraya, buraya, buraya, buraya ve buraya bakın).
iRavi iVooda

ve bunu bir ViewModel içinde kullanmak istersem ne olur? orada android şeylere sahip olmama idealine karşı değil mi?
desgraci

@desgraci, bir ViewModel kullanmadım, ancak dokümantasyondan sadece ViewModel'in görünüm hiyerarşisine erişmemesi veya Aktivite veya Parçaya bir referans içermemesi gerektiğini söylediğini görüyorum. Genel olarak "Android şeylere" sahip olmayı yasaklayan hiçbir şey görmüyorum.
Suragch

Bugün itibariyle bu referanslar benim için modası geçmiş ve dikkate alınacak kadar bilgilendirici değil. Listelenen bu 4 dezavantaj, yalnızca kodunuzu kötü bir şekilde programlarsanız gerçektir. TimerTasks, arka planda periyodik olarak bir şey çalıştırmak ve sonunda, bazı koşullar geçerliyse UIThread üzerinde bir şey çalıştırmak istiyorsanız, hala çok iyi bir seçimdir.
David

18

Zamanlayıcı kullanmanın bazı dezavantajları vardır

Görevleri yürütmek için yalnızca tek bir iş parçacığı oluşturur ve bir görevin çalışması çok uzun sürerse, diğer görevler zarar görür. Görevler tarafından atılan istisnaları işlemez ve sadece iş parçacığı sona erer, bu da diğer zamanlanmış görevleri etkiler ve bunlar asla çalıştırılmaz.

Şuradan kopyalandı:

TimerTask vs Thread.sleep ve Handler post


6
peki ya tek seferlik bir görev için? Belki de bunun için Timer daha iyidir, çünkü mesaj kuyruğunun ek yüküne sahip değilsiniz?
Michael

2
Sanırım asla bilemeyeceğiz
Denny

7

Kabul edilen cevabın Kotlin versiyonu:

val handler = Handler()

val runnableCode = object : Runnable {
    override fun run() {
       Log.d("Handlers", "Called on main thread")
       handler.postDelayed(this, 2000)
    }
}

handler.post(runnableCode)
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.