Android中子线程更新UI的几种方式

本文深入解析了Handler机制在Android中的作用,包括其如何用于发送和处理Message及Runnable对象,以及在不同线程间传递消息的原理。同时,对比了Activity.runOnUiThread、View.post等方法与Handler的关系,揭示了它们在更新UI时的底层实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Handler

先来看下官方对Handler的描述

 A Handler allows you to send and process {@link Message} and Runnable
 objects associated with a thread's {@link MessageQueue}.  Each Handler
 instance is associated with a single thread and that thread's message
 queue.  When you create a new Handler, it is bound to the thread /
 message queue of the thread that is creating it -- from that point on,
 it will deliver messages and runnables to that message queue and execute
 them as they come out of the message queue.
翻译过来的大概意思:Handler允许你发送、执行与线程相关的Message和Runnable对象,每个Handler实例
关联到一个单独的线程和线程中的Message Queue。当创建Handler对象时,它被绑定到所在的线程、
MessageQueue --基于这点,Handler将会发送Message和Runnable到那个MessageQueue中,
并且在那个线程中执行Message和Runnable。

Handler主要有2个使用场景:
(1)计划在未来某个时间点执行Messages和Runnable;
(2)在别的线程中插入一个想要执行的Action;

Handler的使用方式:

//使用Handler执行任务Runnable
//在主线程中构造handler对象,然后在其他线程中调用handler.post方法,则Runnable将会在主线程中被执行
Handler handler = new Handler();
handler.post(new Runnable() {
    @Override
    public void run() {
        //do somethings
    }
});

handler.postDelayed(new Runnable() {
    @Override
    public void run() {
        //do somethings
    }
}, 1000);
//在主线程中构造Handler对象,在其他线程在发送Message,则Message将会在主线程中被接收处理
Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
    }
};
Message msg = Message.obtain();
msg.what = 0x11;
handler.sendMessage(msg);
handler.sendEmptyMessage(0x11);
handler.sendMessageDelayed(msg, 1000);

2、Activity.runOnUiThread(Runnable)

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        //do something
    }
 });

追踪runOnUiThread这个方法,可以发现,方法内部也是使用Handler把Runnable送到主线程中执行。如果调用runOnUiiThread方法时不是处于主线程,则用handler发送Runnable,否则在主线程则直接执行Runnable。

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

3、View.post(Runnable),View.postDelay(Runnable, long)

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

    getRunQueue().post(action);
    return true;
}

跟踪post、postDelay方法,发现,当调用View.post方法时,View已经初始化完毕,会使用Handler发送执行Runnable,否则把Runnable发送到HandlerActionQueue中。HandlerActionQueue这个类保存着将要被Handler处理的Runnable,待View初始化完毕,会从HandlerActionQueue取出Runnable并交由Handler发送执行。

#View.java
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
    mAttachInfo = info;
    ...
    // Transfer all pending runnables.
    //view初始化完,开始执行Runnable
    if (mRunQueue != null) {
       mRunQueue.executeActions(info.mHandler);
       mRunQueue = null;
    }
    ...
}


#HandlerActionQueue.java
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];
            handler.postDelayed(handlerAction.action, handlerAction.delay);
        }
        mActions = null;
        mCount = 0;
    }
}

总结,更新UI的几种方式最终都是通过Handler来实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值