Bir işleyiciden tüm geri aramalar nasıl kaldırılır?


223

Alt Faaliyetimden ana Faaliyet tarafından çağrılan bir İşleyici var . Bu işleyici bazı Runnables alt sınıfları tarafından kullanılır ve onları yönetemiyorum. Şimdi, etkinlikte, Etkinliği bitirmeden önce bunları kaldırmam gerekiyor (bir şekilde aradım , ancak yine de tekrar tekrar çağırıyor). İşleyiciden tüm geri çağrıları kaldırmak için yine de var mı?postDelayonStopfinish()

Yanıtlar:


523

Deneyimime göre bu harika çalıştı!

handler.removeCallbacksAndMessages(null);

RemoveCallbacksAndMessages için belgelerde diyor ...

Bekleyen geri arama gönderilerini ve hedefi belirteci olan gönderilen iletileri kaldırın. Jeton ise null, tüm geri aramalar ve mesajlar kaldırılır.


2
@Malachiasz Etkinlik odak kaybolduktan sonra hiçbir iletinin işlenmediğinden emin olmak için onStop veya onPause'da kullanacağımı düşünüyorum. Ancak geri arama / mesaj tetiklendiğinde ne yapılması gerektiğine bağlıdır
Boy

1
Bunu yaparken bazı telefonlarda daha önce NPE gördüğümü düşünüyorum ama bir süre oldu.
Matt Wolfe

3
removeCallbacksAndMessages(null)Bazı geri aramalarımı kaldırmak olmaz ile ilgili bazı sorunlar yaşadım . Geri Aramaları almayı bırakmak istediğimde, handler.removeCallbacksAndMessages(null)işleyicimi null olarak ayarlayıp çağırırdım, ancak yine de geri aramayı alacağımdan, döngü yapmak istediğimde bir NPE ile karşılaşırdım handler.postDelayed().
Snaker

@Snaker Sorununuzu henüz çözdünüz mü? Handler.Callback null ayarlayarak geri çağrıları ve iletileri kaldırdıktan sonra bile çağrılıyor aynı sorun yaşıyorum.
KaridesCrackers

1
@ShrimpCrackers Runnable bir örnek tutmak ve kullanmak yourHandler.removeCallbacks(yourRunnable)en güvenilir olduğunu öğrendim . Bugün hala kullanıyorum.
Snaker

19

Herhangi bir Runnableörnek için arayın Handler.removeCallbacks(). RunnableHangi geri aramaların kaydını sileceğini belirlemek için örneğin kendisini kullandığını unutmayın; bu nedenle, her gönderi yapıldığında yeni bir örnek oluşturuyorsanız Runnable, iptal etmek için tam olarak referanslara sahip olduğunuzdan emin olmanız gerekir . Misal:

Handler myHandler = new Handler();
Runnable myRunnable = new Runnable() {
    public void run() {
        //Some interesting task
    }
};

Sen diyebilirsin myHandler.postDelayed(myRunnable, x)Kodunuzdaki diğer yerlerde mesaj kuyruğuna başka geri arama göndermek için, ve tüm bekleyen geri aramalar kaldırmakmyHandler.removeCallbacks(myRunnable)

Ne yazık ki, sadece bütününü "temizlemek" değil MessageQueuebir için Handleriçin talepte bile, MessageQueueöğe ekleme ve çıkarma yöntemleri paketi korumalı (onları çağırabilir android.os paket içinde sadece sınıflar) çünkü onunla ilişkili nesne. Gönderildiği / yürütüldüğü gibi Handlerbir listeyi yönetmek için ince bir alt sınıf oluşturmanız gerekebilir Runnableveya mesajlarınızı her biri arasında iletmek için başka bir paradigmaya bakabilirsinizActivity

Umarım yardımcı olur!


Teşekkürler, biliyorum. Ama birçok alt sınıfta çok fazla Runnable var ve hepsini yönetmek destansı bir iş! OnStop () etkinliğinde hepsini kaldırmak için yine de var mı?
Luke Vo

Anladım, cevabı biraz daha bilgi ile güncelledim. Kısa sürüm, bir Handler'ın mesaj kuyruğunu temizlemek için bir yöntem
çağıramazsınız


6

Yeni bir işleyici tanımlayın ve çalıştırılabilir:

private Handler handler = new Handler(Looper.getMainLooper());
private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // Do what ever you want
        }
    };

Çağrı yayını gecikti:

handler.postDelayed(runnable, sleep_time);

Geri aramanızı işleyicinizden kaldırın:

handler.removeCallbacks(runnable);

3

Birinin bir Handlerve bir Runnablesınıf kapsamı tanımlaması gerektiğini unutmayın , böylece bir kez oluşturulur. removeCallbacks(Runnable)biri birden çok kez tanımlamazsa düzgün çalışır. Daha iyi anlamak için lütfen aşağıdaki örneklere bakın:

Yanlış yol:

    public class FooActivity extends Activity {
           private void handleSomething(){
                Handler handler = new Handler();
                Runnable runnable = new Runnable() {
                   @Override
                   public void run() {
                      doIt();
                  }
               };
              if(shouldIDoIt){
                  //doIt() works after 3 seconds.
                  handler.postDelayed(runnable, 3000);
              } else {
                  handler.removeCallbacks(runnable);
              }
           }

          public void onClick(View v){
              handleSomething();
          }
    } 

onClick(..)Yöntemi çağırırsanız , doIt()çağrılmadan önce yöntem çağrısını asla durdurmazsınız . Çünkü her seferinde oluşturur new Handlerve new Runnableörnekler. Bu şekilde, işleyiciye ve çalıştırılabilir örneklere ait gerekli başvuruları kaybettiniz .

Doğru yol :

 public class FooActivity extends Activity {
        Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                doIt();
            }
        };
        private void handleSomething(){
            if(shouldIDoIt){
                //doIt() works after 3 seconds.
                handler.postDelayed(runnable, 3000);
            } else {
                handler.removeCallbacks(runnable);
            }
       }

       public void onClick(View v){
           handleSomething();
       }
 } 

Bu şekilde, gerçek referansları kaybetmezsiniz ve removeCallbacks(runnable)başarıyla çalışırsınız.

Anahtar cümle, 'onları sizin Activityveya Fragmentne kullandığınız konusunda küresel olarak tanımlamak'tır .


1

As josh527dedi handler.removeCallbacksAndMessages(null);çalışabilir.
Ama neden?
Kaynak koduna bir göz attıysanız, kodu daha net anlayabilirsiniz. Geri çağrıları / iletileri işleyiciden (MessageQueue) kaldırmak için 3 tür yöntem vardır:

  1. geri arama ile kaldır (ve jeton)
  2. message.what (ve jetonu) ile kaldır
  3. jetonla kaldır

Handler.java (bazı aşırı yükleme yöntemlerini bırakın)

/**
 * Remove any pending posts of Runnable <var>r</var> with Object
 * <var>token</var> that are in the message queue.  If <var>token</var> is null,
 * all callbacks will be removed.
 */
public final void removeCallbacks(Runnable r, Object token)
{
    mQueue.removeMessages(this, r, token);
}

/**
 * Remove any pending posts of messages with code 'what' and whose obj is
 * 'object' that are in the message queue.  If <var>object</var> is null,
 * all messages will be removed.
 */
public final void removeMessages(int what, Object object) {
    mQueue.removeMessages(this, what, object);
}

/**
 * Remove any pending posts of callbacks and sent messages whose
 * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
 * all callbacks and messages will be removed.
 */
public final void removeCallbacksAndMessages(Object token) {
    mQueue.removeCallbacksAndMessages(this, token);
}

MessageQueue.java gerçek işi yapar:

void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

void removeMessages(Handler h, Runnable r, Object object) {
    if (h == null || r == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.callback == r
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.callback == r
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}

void removeCallbacksAndMessages(Handler h, Object object) {
    if (h == null) {
        return;
    }

    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h
                && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}
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.