처리기에서 모든 콜백을 제거하는 방법은 무엇입니까?


222

기본 Activity 에서 호출 한 하위 활동 의 처리기가 있습니다 . 이 처리기는 하위 클래스에서 일부 Runnable에 사용되며 관리 할 수 ​​없습니다. 이제는 활동을 마치기 전에 제거해야합니다 (어떻게 전화 했지 만 여전히 계속 호출합니다). 처리기에서 모든 콜백을 제거해야합니까?postDelayonStopfinish()

답변:


522

내 경험상 이것을 호출하면 훌륭하게 작동했습니다!

handler.removeCallbacksAndMessages(null);

removeCallbacksAndMessages 문서에서 ...

대기중인 콜백 게시물과 obj가 토큰 인 메시지를 삭제합니다. 토큰이 인 null경우 모든 콜백 및 메시지가 제거됩니다.


2
@Malachiasz 나는 onStop 또는 onPause에서 사용하여 활동이 포커스를 잃은 후에 메시지가 처리되지 않도록 할 것이라고 생각합니다. 그러나 콜백 / 메시지가 실행될 때 수행해야 할 작업에 따라 다름
Boy

1
나는이 작업을 할 때 일부 전화에서 NPE를 본 적이 있다고 생각하지만 오래되었습니다.
매트 울프

3
removeCallbacksAndMessages(null)콜백 중 일부가 제거되지 않는 문제가 있습니다. 콜백 수신을 중단하고 싶을 때는 전화를 걸어 handler.removeCallbacksAndMessages(null)핸들러를 null로 설정하지만 콜백을 계속 얻을 수 있기 때문에와 루프하고 싶을 때 NPE가 발생합니다 handler.postDelayed().
Snaker

@Snaker 아직 문제를 해결하셨습니까? null을 설정하여 콜백과 메시지를 제거한 후에도 Handler.Callback이 호출되는 것과 동일한 문제가 있습니다.
ShrimpCrackers

1
@ShrimpCrackers 런너 블 인스턴스를 유지하고 사용하는 yourHandler.removeCallbacks(yourRunnable)것이 가장 신뢰할 수 있음을 알았습니다 . 오늘도 여전히 사용하고 있습니다.
Snaker

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 () 이벤트에서 그것들을 모두 제거해야합니까?
Luke 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

클래스 범위에서 HandlerRunnable클래스를 정의하여 한 번만 작성해야합니다. 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);작업 할 수 있습니다.
그런데 왜?
소스 코드를 살펴보면 더 명확하게 이해할 수 있습니다. 핸들러 (MessageQueue)에서 콜백 / 메시지를 제거하는 방법에는 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.