Handler的使用大家都很熟悉,今天做一下关于Handler的总结,方便以后使用。

为什么用Handler

UI线程是非安全线程,不能进行耗时操作,子线程做耗时操作,不能更新UI,否则会出现程序长时间假死状态,即ANR,程序无响应异常。为了解决以上问题,Android设计了Handler机制,由Handler来负责与子线程进行通讯,从而让子线程与主线程之间建立起协作的桥梁,使Android的UI更新的问题得到完美的解决。

Handler的作用:

1. 在新启动的线程中发送消息;2. 在主线程中获取、处理消息。

Handler和Looper

 Message:消息体 Handler:负责发送消息sendMessage(message),接收消handleMessage(Message msg) Looper:消息泵,用来管理特定线程内对象之间的消息交换,一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列)。主要包含两个方法Looper.prepare(),Looper.loop()Message Queue:消息队列,存放线程放入的消息UI线程:主线程,启动的时候会创建消息队列已经 给线程创建一个消息循环Looper.prepare()
@Overridepublic void run() {  try {    // preparing a looper on current thread     // the current thread is being detected implicitly    Looper.prepare();    // now, the handler will automatically bind to the    // Looper that is attached to the current thread    // You don't need to specify the Looper explicitly    handler = new Handler();    // After the following line the thread will start    // running the message loop and will not normally    // exit the loop unless a problem happens or you    // quit() the looper (see below)    Looper.loop();  } catch (Throwable t) {    Log.e(TAG, "halted due to an error", t);  } }

上面理论上看起来理解不是很理想,下面我找了几张图来方便理解。

Looper.prepare():

可以看出通过prepare()方法,创建了线程和消息队列。下面我们看源码

public class Looper {    // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象    private static final ThreadLocal sThreadLocal = new ThreadLocal();    // Looper内的消息队列    final MessageQueue mQueue;    // 当前线程    Thread mThread;    // 。。。其他属性    // 每个Looper对象中有它的消息队列,和它所属的线程    private Looper() {        mQueue = new MessageQueue();        mRun = true;        mThread = Thread.currentThread();    }    // 我们调用该方法会在调用线程的TLS中创建Looper对象    public static final void prepare() {        if (sThreadLocal.get() != null) {            // 试图在有Looper的线程中再次创建Looper将抛出异常            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper());    }    // 其他方法}

prepare()会new Looper()创建一个Looper对象,对象里面分别又创建了线程和MQ。由此可知一个Thread只能有一个Looper对象对应一个MQ,三者一一对应。

Looper.loop():

Looper会不断从MQ中取出消息头执行,并推送给Handler执行。

Handler发送消息:

一个线程可以有多个Handler,但是只能有一个Looper!Handler发送消息通过Looper添加到MQ。

Handler处理消息:

Looper取出消息头,Handler执行,完毕后返回Looper继续执行。

总流程:

使用案例

子线程向主线程发送消息:

new Thread(new Runnable() {                    @Override                    public void run() {                        MyHandler handler = new MyHandler(getMainLooper());                        Message message = new Message();                        message.obj = "子线程发送的消息";                        handler.sendMessage(message);                    }                }).start();    class MyHandler extends Handler {        public MyHandler(Looper looper) {            super(looper);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            Log.e("TAG", msg.obj.toString());        }    }

主线程向子线程发送消息:

 class TestThread extends Thread {        private Handler handler;        @Override        public void run() {            super.run();            Looper.prepare();            handler=new Handler(getMainLooper()){                @Override                public void handleMessage(Message msg) {                    super.handleMessage(msg);                    Log.e("TAG",msg.obj.toString());                }            };            Looper.loop();        }    }

主线程发送:

 new TestThread().handler.sendEmptyMessage(0);

Handler的post()方法:

 new Thread(){    @Override                public void run() {                      mHandler.post(new Runnable() {                          @Override                          public void run() {                           //更新UI                        }                      });                  };              }.start();

runOnUiThread()方法:

 new Thread(){                  public void run() {                      mActivity.runOnUiThread(new Runnable() {                          @Override                          public void run() {       //更新UI                        }                      });                  };              }.start();  

post和runOnUiThread都可以在子线程中更新UI,但是实际上他们是将消息post到UI线程中处理,所以run()里面不能做耗时操作。

更多相关文章

  1. Android(安卓)消息机制学习
  2. Android实现定时执行某个任务
  3. Android服务器推送之GCM
  4. Android-- Toast通知的用法
  5. Unity3D 与Android(安卓)相互传递消息
  6. Android线程池的使用
  7. Volley源码解析
  8. Android应用程序消息处理机制(Looper、Handler)分析(3)
  9. Android基础之异步消息处理机制

随机推荐

  1. juniper-SRX FW ssh登录被拒绝问题
  2. 项目管理神书---PMP认证官方教材PMBOK
  3. 销售小白如何才能充分发挥CRM的作用呢?
  4. [iOS初级教程之三]Crash分析实践
  5. 如何让 iPhone 自带日历 App 显示国家法
  6. Oracle OCP 071中文考试题库-第15题
  7. 随笔
  8. 阿里云盘来袭,送几个福利码!手慢无!
  9. 什么是增强分析?增强分析如何改善传统BI工
  10. C语言中static 试题