हैंडलर से सभी कॉलबैक कैसे निकालें?


222

मेरे पास मेरी उप-गतिविधि से एक हैंडलर है जिसे मुख्य गतिविधि द्वारा बुलाया गया था । यह हैंडलर उप-वर्गों द्वारा postDelayकुछ Runnables के लिए उपयोग किया जाता है , और मैं उन्हें प्रबंधित नहीं कर सकता। अब, onStopघटना में, मुझे गतिविधि को समाप्त करने से पहले उन्हें निकालने की आवश्यकता है (किसी तरह मैंने फोन किया finish(), लेकिन यह अभी भी बार-बार कॉल करता है)। क्या किसी हैंडलर से सभी कॉलबैक को हटाने के लिए कुछ भी है?

जवाबों:


522

मेरे अनुभव में यह महान काम कर रहा है!

handler.removeCallbacksAndMessages(null);

हटाने के लिए दस्तावेज़ों में यह कहता है

कॉलबैक और भेजे गए संदेशों के किसी भी लंबित पोस्ट को हटा दें, जिसका obj टोकन है। यदि टोकन है null, तो सभी कॉलबैक और संदेश हटा दिए जाएंगे।


2
@ मैलाचियाज़ मुझे लगता है कि मैं इसे onStop या onPause में इस्तेमाल करूंगा, यह सुनिश्चित करने के लिए कि गतिविधि खो जाने के बाद कोई संदेश हाथ न लगे। लेकिन कॉलबैक / संदेश निकाल दिए जाने पर क्या करने की जरूरत है पर निर्भर करता है
लड़का 13

1
मुझे विश्वास है कि मैंने ऐसा करते समय कुछ फोन पर एनपीई देखा है, लेकिन कुछ समय हो गया है।
मैट वोल्फे

3
मेरे पास कुछ समस्याएँ हैं, removeCallbacksAndMessages(null)जो मेरे कुछ कॉलबैक को नहीं हटाएंगी। जब मैं कॉलबैक प्राप्त करना बंद करना चाहूंगा, तो मैं कॉल handler.removeCallbacksAndMessages(null)करूंगा और अपने हैंडलर को अशक्त कर दूंगा, लेकिन जब से मुझे कॉलबैक मिलेगा, तब मैं एनपीई से भिड़ जाऊंगा, जब मैं लूप करना चाहता हूं handler.postDelayed()
संस्कार

@Snaker क्या आपने अभी तक अपनी समस्या हल की है? मेरे पास एक ही मुद्दा है जहां हैंडलर.कॉलबैक को अशक्त करके कॉलबैक और संदेशों को हटाने के बाद भी कॉल किया जा रहा है।
झींगा पटाखे 3

1
@SrimpCrackers मैंने पाया कि आपके रन करने योग्य और उपयोग करने yourHandler.removeCallbacks(yourRunnable)का एक उदाहरण सबसे विश्वसनीय था। आज भी उसी का उपयोग कर रहे हैं।
संस्कार

19

किसी भी विशिष्ट Runnableउदाहरण के लिए, कॉल करें Handler.removeCallbacks()। ध्यान दें कि यह Runnableस्वयं का उपयोग करता है यह निर्धारित करने के लिए कि कौन सी कॉलबैक को अपंजीकृत किया जाता है, इसलिए यदि आप हर बार एक पोस्ट करने के बाद एक नया उदाहरण बना रहे हैं, तो आपको यह सुनिश्चित करने की आवश्यकता है कि आपके पास Runnableरद्द करने के लिए सटीक संदर्भ हैं । उदाहरण:

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

आप myHandler.postDelayed(myRunnable, x)अपने कोड में अन्य स्थानों पर संदेश कतार में एक और कॉलबैक पोस्ट करने के लिए कॉल कर सकते हैं, और सभी लंबित कॉलबैक को हटा सकते हैंmyHandler.removeCallbacks(myRunnable)

दुर्भाग्य से, आप MessageQueueएक के लिए पूरी तरह से "स्पष्ट" नहीं कर सकते हैं Handler, भले ही आप MessageQueueइसके साथ जुड़े ऑब्जेक्ट के लिए अनुरोध करें क्योंकि आइटम जोड़ने और हटाने के तरीके पैकेज संरक्षित हैं (केवल android.os पैकेज के भीतर वर्ग उन्हें कॉल कर सकते हैं)। जैसा कि वे पोस्ट किए गए / निष्पादित किए जाते हैं, आपको Handlerएक सूची का प्रबंधन करने के लिए एक पतली उपवर्ग बनाना पड़ सकता है Runnable... या प्रत्येक के बीच अपने संदेश पारित करने के लिए एक और प्रतिमान देखेंActivity

उम्मीद है की वो मदद करदे!


धन्यवाद, मुझे पता है कि लेकिन मेरे पास कई उप-वर्गों में बहुत सारे रननेबल हैं, और उन सभी को प्रबंधित करना एक महाकाव्य काम है! वहाँ वैसे भी उन सब को हटाने के लिए है, onStop () ईवेंट में?
ल्यूक वो

समझ में आया, मैंने उत्तर को थोड़ी और जानकारी के साथ अद्यतन किया। लघु संस्करण आप एक विधि को मोटे तौर पर एक हैंडलर संदेश कतार को साफ करने के लिए नहीं कह सकते ...
Devunwired

8

यदि आपके पास पहले कॉलबैक पर रन करने योग्य संदर्भ नहीं हैं, तो संदेश का लाभ प्राप्त करें, और सभी संबंधित कॉलबैक को हटाने के लिए removeCallbacksAndMessages () का उपयोग करें ।


6

नया हैंडलर परिभाषित करें और चलाने योग्य:

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

कॉल पोस्ट में देरी हुई:

handler.postDelayed(runnable, sleep_time);

अपने हैंडलर से अपना कॉलबैक निकालें:

handler.removeCallbacks(runnable);

3

कृपया ध्यान दें कि एक को एक Handlerऔर एक Runnableवर्ग के दायरे में परिभाषित किया जाना चाहिए , ताकि इसे एक बार बनाया जाए। removeCallbacks(Runnable)सही ढंग से काम करता है जब तक कि कोई उन्हें कई बार परिभाषित न करे। कृपया बेहतर समझ के लिए निम्नलिखित उदाहरण देखें:

गलत तरीका:

    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(..)विधि करते हैं, तो आप कॉल करने doIt()से पहले कभी भी विधि कॉलिंग को बंद नहीं करेंगे। क्योंकि प्रत्येक समय सृजन new Handlerऔर new Runnableउदाहरण देता है। इस तरह, आपने आवश्यक संदर्भ खो दिए हैं जो हैंडलर और रन करने योग्य उदाहरणों से संबंधित हैं ।

सही तरीका :

 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();
       }
 } 

इस तरह, आप वास्तविक संदर्भों और removeCallbacks(runnable)कार्यों को सफलतापूर्वक नहीं खोते हैं ।

मुख्य वाक्य यह है कि 'उन्हें अपने Activityया Fragmentआपके द्वारा उपयोग किए जाने वाले वैश्विक के रूप में परिभाषित करें'


1

जैसा josh527कहा गया है, handler.removeCallbacksAndMessages(null);काम कर सकते हैं।
पर क्यों?
यदि आपके पास स्रोत कोड पर एक नज़र है, तो आप इसे और अधिक स्पष्ट रूप से समझ सकते हैं। हैंडलबार (मैसेजक्यूएयू) से कॉलबैक / मैसेज को हटाने के लिए 3 प्रकार की विधि है:

  1. कॉलबैक से हटाएं (और टोकन)
  2. संदेश द्वारा निकालें। क्या (टोकन)
  3. टोकन द्वारा हटा दें

हैंडलर.जावा (कुछ अधिभार विधि छोड़ें)

/**
 * 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 असली काम करते हैं:

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;
        }
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.