安卓学习笔记之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一样,都是直接发送消息到主消息队列。
相关文章推荐
- HDU 1242 Rescue(bfs+优先队列)
- 通过可变字符串在UILabel上面加横线
- 自定义UICollectionViewFlowLayout
- androidStudio中出现finished with non-zero exit value 2 或者 finished with non-zero exit value 1
- IOS开发-UI学习-使用代码创建button
- OSSIM入门视频推出WebUI菜单自定义和汉化方法视频教程
- dispatch_queue_set_specific和dispatch_get_specific
- lintcode-medium-Longest Increasing Subsequence
- iOS: 使用CGContextRef,CGPath和UIBezierPath来绘画
- UESTC 1297 Bank 思维题
- Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. 错误解决
- 被废弃的dispatch_get_current_queue
- iOS之解决UITableView与背景颜色不一致问题
- Codeforces 652E Pursuit For Artifacts 【边双连通 缩点】
- UEditor编辑器的使用
- UITransitionView and UILayoutContainerView 详解
- 通过UIColor颜色创建UIImage
- SqlParameter设定value为0却变成null
- OBS Build on ubuntu14.04
- ASIFormDataRequest实现post的代码示例