ハンドラーからすべてのコールバックを削除する方法は?


222

メインアクティビティによって呼び出されたサブアクティビティからのハンドラがあります。このハンドラは一部のRunnableのサブクラスで使用されており、管理できません。さて、イベントでは、アクティビティを完了する前にそれらを削除する必要があります(どういうわけかを呼び出しましたが、それでも何度も繰り返し呼び出します)。ハンドラからすべてのコールバックを削除する方法はありますか?postDelayonStopfinish()

回答:


522

私の経験では、これを呼び出すのはうまくいきました!

handler.removeCallbacksAndMessages(null);

removeCallbacksAndMessagesのドキュメントでは、それは言う...

objがトークンであるコールバックと送信メッセージの保留中の投稿をすべて削除します。トークンがの場合null、すべてのコールバックとメッセージが削除されます。


2
@Malachiaszアクティビティがフォーカスを失った後にメッセージが処理されないようにするために、onStopまたはonPauseで使用すると思います。しかし、コールバック/メッセージが発生したときに何をする必要があるかによって異なります
Boy

1
これを行うときに、一部の電話で以前にNPEを見たことがあると思いますが、久しぶりです。
Matt Wolfe、

3
removeCallbacksAndMessages(null)一部のコールバックを削除できないという問題がありました。コールバックの受信を停止する場合は、呼び出しhandler.removeCallbacksAndMessages(null)てハンドラーをnullに設定しますが、それでもコールバックを取得するため、でループするときにNPEが発生しますhandler.postDelayed()
Snaker

@Snaker問題はもう解決しましたか?nullを設定してコールバックとメッセージを削除した後でもHandler.Callbackが呼び出されるのと同じ問題があります。
エビクラッカー2017

1
@ShrimpCrackers実行可能なインスタンスを維持し、使用することyourHandler.removeCallbacks(yourRunnable)が最も信頼できることがわかりました。今日もそれを使用しています。
スネーカー2017

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)

残念ながら、項目に追加および削除するメソッドはパッケージで保護されているため(android.osパッケージ内のクラスのみがそれらを呼び出すことができるため)、関連付けられているオブジェクトをリクエストしても、の全体MessageQueueを単純に「クリア」することはできません。投稿/実行されたsのリストを管理するために薄いサブクラスを作成する必要があるかもしれません...またはそれぞれの間でメッセージを渡すための別のパラダイムを確認してくださいHandlerMessageQueueHandlerRunnableActivity

お役に立てば幸いです。


ありがとう、私はそれを知っています。しかし、私は多くのサブクラスで多くのRunnableを使用しており、それらすべてを管理することは壮大な作業です!とにかく、それらすべてをonStop()イベントで削除する方法はありますか?
ルークVo

理解しました。答えをもう少し詳しく更新しました。短いバージョンでは、ハンドラーのメッセージキューを広くクリアするメソッドを呼び出すことができません...
Devunwired


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

1つが作成されるように、クラスのスコープ内でHandlerとを定義する必要があることに注意してくださいRunnableremoveCallbacks(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. message.what(およびトークン)で削除
  3. トークンで削除

Handler.java(いくつかのオーバーロードメソッドを残す)

/**
 * 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;
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.