滴水穿石
有些事情深入本质才能理解通透。
同步服务器时间
很久没有写过了,这几个月忙着赶项目(996 -_-!!),出差,健身再加上自己心态也松懈了,从今天开始 有时间还是需要记录一些东西。
今天在使用handler加runnable维护一个本地时钟的时候,由于疏忽,遇到了一个小问题,在此记录,希望有人看过之后能有所启发。
Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { mServerTime++; handler.postDelayed(this, 1000); } };
由于项目的特殊,只需要在某个特定的地方请求服务器时间,然后将拿到的时间set到mServerTime,然后在通过handler.postDelayed();来维护一个自动跑的时钟,我们先来看下postDelayed里面有什么。
public final boolean postDelayed(Runnable r, long delayMillis) { return sendMessageDelayed(getPostMessage(r), delayMillis); }看不出什么,继续看getPostMessage(r)。
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); }
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }我想看到这里,大家应该明白了,handler.postDelayed();这个方法将线程放进一个message里面,再将这个message根据时间(开机到现在的时间加上你设置的延时时间)放入到系统的消息队列里面。
因为我的app在某个点会去调用handler.postDelayed()来实时同步服务器时间,由于开始的疏忽,没有在第二次postDelayed之前将之前的removeCallbacks掉,所以当多次调用这个的时候,MessageQueue会同时存在多个相同的message,由于每次runnable使时间增加一秒,这样导致每秒使我维护的时钟增加多秒,所以,大家在使用的时候记得根据需求进行handler.removeCallbacks(runnable)。