安卓事件处理---Handler消息处理机制

本文介绍了Android中的Handler消息处理机制,用于解决子线程更新UI的问题。Handler、Message、MessageQueue和Looper之间的协作使得子线程能与主线程进行通信。Handler主要通过sendXXX()和postXXX()方法发送消息或计划任务,同时讲解了如何在子线程中使用Handler更新UI的步骤。

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

1、为什么要有handler机制?

当应用程序启动时,会开启一个主线程(也就是UI线程),由她来管理UI,监听用户点击,来响应用户并分发事件等。所以一般在主线程中不要执行比较耗时的操作,如联网下载数据等,否则出现ANR(应用无响应)错误。所以就将这些操作放在子线程中,但是由于Android子线程是不安全的,所以只能在主线程中更新UI。Handler就是用来 子线程和创建Handler的线程进行通信的。

        为了解决以上问题,Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁,使Android的UI更新的问题得到完美的解决。

2、Handler的工作原理

在下面介绍Handler机制前,首先得了解以下几个概念:
Message 消息,理解为线程间通讯的数据单元。例如后台线程在处理数据完毕后需要更新UI,则可发送一条包含更新信息的Message给UI线程。
Message Queue 消息队列,用来存放通过Handler发布的消息,按照先进先出执行。
Handler Handler是Message的主要处理者,负责将Message添加到消息队列以及对消息队列中的Message进行处理。
Looper 循环器,扮演Message Queue和Handler之间桥梁的角色,循环取出Message Queue里面的Message,并交付给相应的Handler进行处理。
线程 UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。


与Handle工作的几个组件Looper、MessageQueue各自的作用:
  1.Handler:它把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息
   2.MessageQueue:采用先进的方式来管理Message
   3.Looper:每个线程只有一个Looper,比如UI线程中,系统会默认的初始化一个Looper对象,它负责管理MessageQueue,不断的从MessageQueue中取消息,并相对应的消息分给Handler处理


Handler,Looper和MessageQueue就是简单的三角关系。

Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。
而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。
这样说来,多个Handler都可以共享同一Looper和MessageQueue了。
这些Handler也就运行在同一个线程里,每个线程一个Loop而 一个MessageQueue。



handler类有两种主要用途: 
1、按照时间计划,在未来某时刻,对处理一个消息或执行某个runnable实例。 
2、把一个对另外线程对象的操作请求放入消息队列中,从而避免线程间冲突。


三、Handler机制的使用

Handler工具类在多线程中有两方面的应用:

1、发送消息,在不同的线程间发送消息,使用的方法为sendXXX(); 
android.os.Handler对象通过下面的方法发送消息的: 
sendEmptyMessage(int),发送一个空的消息; 
sendMessage(Message),发送消息,消息中可以携带参数; 
sendMessageAtTime(Message, long),未来某一时间点发送消息; 
sendMessageDelayed(Message, long),延时Nms发送消息。


2、计划任务,在未来执行某任务,使用的方法为postXXX(); 
android.os.Handler对象通过下面的方法执行计划任务: 
post(Runnable),提交计划任务马上执行; 
postAtTime(Runnable, long),提交计划任务在未来的时间点执行; 
postDelayed(Runnable, long),提交计划任务延时Nms执行。



使用 Handler 在子线程中向 UI 线程发送一个消息进行 UI 的更新
创建一个 Message, Message msg = new Message(); msg.arg1 = 88;
handler.sendMessage(msg); msg.obj = xxx; 可以传递一个对象
当然不一定要用 new 一个 Message,也可以复用系统的 message 对象 Message msg = handler.obtainMessage();


在线程中使用Handler的步骤:
 1.调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会自动的创建相对应的MessageQueue
  2.创建Handler子类的实例,重写HandleMessage()方法,该方法处理除UI线程以外线程的消息
  3.调用Looper的loop()方法来启动Looper


四、 Handler 与子线程

4.1 自定义与线程相关的 Handler

class MyThread extends Thread {
    public Handler handler;
    @Override
    public void run() {
        Looper.prepare(); //new 一个Looper对象
        handler = new Handler() { //拿到当前线程的 Looper 对象
            @Override
            public void handlerMessage(Message msg) {
                // TODO Auto-generated method stub
                System.out.println("current thread:" + Thread.currentThread());
            }
        };
        Looper.loop();//开始死循环处理消息
    };
}

一般 UI 主线程中不要执行一些耗时的操作,这样就可以通过子线程消息来处理耗时操作。

4.2 HandlerThread是什么?

HandlerThread 继承于 Thread,所以它本质就是个 Thread。与普通的 Thread 的差别就在于,它有个 Looper 成员变量。这个 Looper 其实就是对消息队列以及队列处理逻辑的封装,简单来说就是消息队列+消息循环。

当我们需要一个工作线程,而不是把它当作一次性消耗品,用过即废的话,就可以使用它

private Handler mHandler = null;
private HandlerThread mHandlerThread = null;

private void sendRunnableToWorker(Ruannable run) {
    if (null == mHandlerThread) {
        mHandlerThread = new HandlerThread("WorkerThread");
        // 给工作者线程低优先级
        mHandlerThread.setPriority(Thread.MIN_PRIORITY);
        mHandlerThread.start();
    }
    if (null == mHandler) {
        mHandler = new Handler(mHandlerThread.getLooper());
    }
    mHandler.post(run);
}


五、主线程与子线程之间的信息交互

//创建主线程的Handler
private Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        Message mssage = new Message();
        System.out.println("main Handler");
        //向子线程发送消息
        threadHandler.sendMessageDelayed(message, 1000);
    };
};
//创建子线程的 handler
private Handler threadHandler;

@Override
protected void onCreate(Bundle saveInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    HandlerThread thread = new HandlerThread("handlerThread");
    //创建子线程的 handler
    threadHandler = new Handler(thread.getLooper()) {
        public void handlerMessage(Message msg) {
            Message message = new Message();
            //向主线程发送消息
            mHandler.sendMessageDelayed(message, 1000);
        };
    };
}

六、Android 中更新 UI 的几种方式
Android 中更新 UI 的 4 种方式
runOnUiThread
handler 的 post
handler 的 sendMessage
View 自身的 post


参考文章:

http://it.51xw.net/mobile/1000b7.html

http://blog.csdn.net/llayjun/article/details/51178271

http://www.jianshu.com/p/520472d7b2e5

http://blog.csdn.net/francisshi/article/details/38550221

http://www.cnblogs.com/xunzhi/p/5671410.html

http://blog.csdn.net/lmj623565791/article/details/38377229/

http://blog.csdn.net/x605940745/article/details/13001279

http://www.2cto.com/kf/201507/419744.html

http://www.cnblogs.com/tero/p/5304118.html

http://www.cnblogs.com/JczmDeveloper/p/4403129.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值