Android中Handler详解

Handler在Android中有着重要的作用,学习Handler能清晰的理解Android线程消息传递机制。

什么是Handler?

Android官方文档给出的解释是:一个Handler允许你发送和处理Message和与某一线程相关联的Runnable对象。每一个Handler实例都与一个单一的线程和他的消息队列相关联。当你创建了一个新的Handler,这个Handler就绑定到了这个线程或者消息队列,将会分发这个消息和runnable到消息队列中,并在他们出队列的时候执行。

Handler重要有两个应用场景:
1.安排一个消息或者runnable在未来的某个时间点执行
2.在其他线程执行你的方法
消息队列完成的方法包括
1. post(Runnable)
2. postAtTime(Runnable, long)
3. postDelayed(Runnable, long)
4. sendEmptyMessage(int)
5. sendMessage(Message)
6. sendMessageAtTime(Message, long)
7. sendMessageDelayed(Message, long)
这里包含post的允许你传入一个runnable对象进入队列而被消息队列唤起,而sendMessage允许你把一个消息传入队列,这个消息包含绑定的数据,这个消息将会被handlerMessage(Message)所处理。

Handler的应用背景

上面大致讲了一下Handler在官方文档上的描述,下面讲一下Handler的应用背景。
当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程。

  Android的UI操作并不是线程安全的(出于性能优化考虑),意味着如果多个线程并发操作UI线程,可能导致线程安全问题。

  为了解决Android应用多线程问题—Android平台只允许UI线程修改Activity里的UI组建,就会导致新启动的线程无法改变界面组建的属性值。

Handler更新UI的方法

1.在主线程中声明:

private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            // TODO 接收消息并且去更新UI线程上的控件内容
            if (msg.what == UPDATE) {
                // 更新界面上的textview
                tv.setText(String.valueOf(msg.obj));
            }
            super.handleMessage(msg);
        }
    };

子线程处理完成任务后发送消息到上面:

new Thread() {
            @Override
            public void run() {
                // TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值
                try {
                       //do something

                        Message msg = new Message();
                        msg.what = UPDATE;                  
                        msg.obj = "更新后的值" ;
                        handler.sendMessage(msg);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

Handler源码分析

Handler中主要有四个构造函数:
1.public Handler()
2.public Handler(Callbackcallback)
3.public Handler(Looperlooper)
4.public Handler(Looperlooper, Callbackcallback)

第1个和第2个构造函数都没有传递Looper,但源码注释中说了(Default constructor associates this handler with the {@link Looper} for the current thread.)就是说这两个构造函数都将通过调用Looper.myLooper()获取当前线程绑定的Looper对象,然后将该Looper对象保存到名为mLooper的成员字段中。

final Looper mLooper;


public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

后两个构造方法则将Looper赋值到mlooper中

public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

这里的Handler消息传递的整体图为:
这里写图片描述

这里写图片描述

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。
MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。
Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。
Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

在Android开发中主要的使用方法

1在主线程中定义Handler

Handler mHandler = new Handler() {  

        @Override  
        public void handleMessage(Message msg) {  
            super.handleMessage(msg);  
            switch (msg.what) {  
            case 0:  
                String data = (String)msg.obj;    
                updateUI();  
                textView.setText(data);  
                break;  
            default:  
                break;  
            }  
        }  
    };  
private void update() {  


        new Thread(new Runnable(){  

            @Override  
            public void run() {  
                //耗时操作,完成之后发送消息给Handler,完成UI更新;              
                //需要数据传递,用下面方法;  
                Message msg =new Message();  
                msg.obj = "数据";//可以是基本类型,可以是对象,可以是List、map等;  
                mHandler.sendMessage(msg);  
            }  

        }).start();  

    }  

2 用Activity对象的runOnUiThread方法更新

new Thread() {  
            public void run() {  
                //这儿是耗时操作,完成之后更新UI;  
                runOnUiThread(new Runnable(){  

                    @Override  
                    public void run() {  
                        //更新UI  
                        imageView.setImageBitmap(bitmap);  
                    }  

                });  
            }  
        }.start();  

或者

Activity activity = (Activity) imageView.getContext();  
               activity.runOnUiThread(new Runnable(){  
                    @Override  
                    public void run() {
                    imageView.setImageBitmap(bitmap);  
                    }  
                });  

3View.post(Runnable r)

imageView.post(new Runnable(){  

                    @Override  
                    public void run() {  
                     imageView.setImageBitmap(bitmap);  
                    }  

                });  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值