您的位置:首页 > 产品设计 > UI/UE

安卓学习笔记之Handler更新UI的几种方法及对比

2016-03-29 13:25 531 查看

Handler更新UI的几种方法

handler发送消息msg的方式

调用handler的post(Runnable)方法

runOnUiThread(Runnable)方法

控件view调用自身的post(Runnable)方法

注意:view.post方法的使用,该view一定是会被添加到视图层级中的,否则无效。

实例代码:

// 第一种
public void handlerpost() {
handler.post(new Runnable() {

@Override
public void run() {
tv.setText("handlerpost更新啦");
}
});
}
//第二种
public void runUI() {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv.setText("runUI更新啦");

}
});
}

//第三种
public void sendmessage() {
handler.sendEmptyMessage(1);
}

//第四种
public void viewpost() {
tv.postDelayed(new Runnable() {

@Override
public void run() {
tv.setText("view更新啦");

}
}, 0);
}


几种常见更新方式的执行顺序对比

考虑如下代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup root = (ViewGroup) LayoutInflater.from(this).inflate(R.layout.activity_main, null);
setContentView(root);

final Button button = new Button(this);
root.addView(button);
button.setText("add-view-test");

// 1
button.post(new Runnable() {
@Override
public void run() {
Log.e(TAG, "button.post");
Toast.makeText(getApplicationContext(), "button.post", Toast.LENGTH_SHORT).show();
}
});

// 2
getWindow().getDecorView().post(new Runnable() { // Decor的dispatchAttachedToWindow最先被调用
@Override
public void run() {
Log.e(TAG, "decor.post");
Toast.makeText(getApplicationContext(), "decor.post", Toast.LENGTH_SHORT).show();
}
});

// 3
handler.post(new Runnable() {
@Override
public void run() {
Log.e(TAG, "handler.post");
Toast.makeText(getApplicationContext(), "handler.post", Toast.LENGTH_SHORT).show();
}
});

// 4
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e(TAG, "runOnUiThread");
Toast.makeText(getApplicationContext(), "runOnUiThread", Toast.LENGTH_SHORT).show();
}
});

new Thread() {
@Override
public void run() {
super.run();
SystemClock.sleep(3000);
handler.post(new Runnable() { // post到UI线程执行
@Override
public void run() {
button.setText("change text");
}
});
}
}.start();
}


上述几种方式的log打印顺序?

执行时间顺序:

4 -> 3 -> 2 -> 1

如下:

E/MainActivity: runOnUiThread

E/MainActivity: handler.post

E/MainActivity: decor.post

E/MainActivity: button.post

分析:

@Override
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}


runOnUiThread在主线程调用,直接执行action.run(); 因此最快

再看Handler:

public final boolean post(Runnable r)
{
return  sendMessageDelayed(getPostMessage(r), 0);
}


handler.post会发送消息到主线程来执行,紧跟其后执行。

1和2都调用了view的post方法

public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}

// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}


此处注意代码调用的时机,在onCreate执行时,view还没有attach到window,所以mAttachInfo=null,所以走getRunQueue().post(action); 并将Runnable添加到了getRunQueue()得到的mRunQueue中。当onResume执行时,才会调用View的dispatchAttachedToWindow,然后才对Runnable做处理。

2比1快?

因为DecorView是顶级View,它的dispatchAttachedToWindow最先被调用,在该方法中会处理post的Runnable:

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
...
// Transfer all pending runnables.
// 处理Runnable
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
performCollectViewAttributes(mAttachInfo, visibility);
onAttachedToWindow();

ListenerInfo li = mListenerInfo;
final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners =
li != null ? li.mOnAttachStateChangeListeners : null;
if (listeners != null && listeners.size() > 0) {
// NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to
// perform the dispatching. The iterator is a safe guard against listeners that
// could mutate the list by calling the various add/remove methods. This prevents
// the array from being modified while we iterate it.
for (OnAttachStateChangeListener listener : listeners) {
listener.onViewAttachedToWindow(this);
}
}

...
onVisibilityChanged(this, visibility);
...
}


mRunQueue.executeActions(info.mHandler);

public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
// 遍历mActions,并将Runnable post到主线程消息队列
handler.postDelayed(handlerAction.action, handlerAction.delay);
}

mActions = null;
mCount = 0;
}
}


当View已经attach到了window时,view.post与handler.post一样,都是直接发送消息到主消息队列。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: