Android Handler.postDelayed digging

platform

  RK3288 + Android 7.1 + AndroidStudio 4.0.1

problem

    Use Handler

Handler.postDelayed(Runnable, Int)

    When, the code in Runnable.run is not executed

analysis

  Handler part of the code:

    static class H extends Handler{
        final static int MSG_REFRESH_TIME = 0;
        WeakReference<KidsLauncher> a;
        H(KidsLauncher lk){
            a = new WeakReference<>(lk);
        }

        @Override
        public void handleMessage(Message msg) {
            switch(msg.what){
                case MSG_REFRESH_TIME:
                    a.get().refreshTime();
                    break;
            }
        }

        /*@Override
        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
            Logger.d("sendmessageAtTime " + msg.what + " " + uptimeMillis + ":" + SystemClock.uptimeMillis());
            return super.sendMessageAtTime(msg, uptimeMillis);
        }*/
    }


    void refreshTime(){
        tvTime.setText(TimeUtils.getTimeString());
        h.removeMessages(H.MSG_REFRESH_TIME);
        h.sendEmptyMessageDelayed(H.MSG_REFRESH_TIME, 1000);
    }

Solutions tried:

  1. Use new Handler().postDelayed => the problem remains
  2. Use new Handler().postDelayed, delayed = 0 => the problem is solved, but it cannot be delayed
  3. Use Handler.post() => the problem is solved, but it cannot be delayed
  4. Use Handler.sendEmptyMessageDelayed => problem solved
  5. Use Handler.sendMessageDelayed => problem solved
  6. Use View.postDelayed => the problem remains

Check the relevant source code and articles:

 

Handler sendMessageDelayed()/postDelayed() mechanism in detail

 

Try to let go of the above comment code, output LOG, and finally found the problem.

solve

Reason: In the application, define a message type as  MSG_REFRESH_TIME=0 ; after startup, the current time will be updated cyclically.

Consider the following question: After Handler.post, when finally enqueueMessage, what is Message. What ? The  answer is 0

//frameworks/base/core/java/android/os/Handler.java

    public final boolean postDelayed(Runnable r, long delayMillis)
    {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }



    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

Whether it is new Message() or Message.obtain(), at the beginning, it is basically 0

Look at the following code:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        h = new H(this);
        h.postDelayed(new Runnable() {
            @Override
            public void run() {
                Logger.d("run in post Delayed");
            }
        }, 2000);
        h.removeMessages(0);
    }

The LOG " run in post Delayed " in the code will not be printed out because the Message has been removed from the queue.

Similarly, after the update time of use MSG_REFRESH_TIME performed refreshTime, the queue, with all of the Message has been Runnable H. The removeMessages (H.MSG_REFRESH_TIME); out of the queue.

So the problem is, dig the hole yourself, then bury yourself...

 

 

Guess you like

Origin blog.csdn.net/ansondroider/article/details/107615957