Handler消息传递机制

    这段时间准备面试,重新将Handler的消息传递机制回顾了一遍,解决了原先认识的一些盲点。

    首先来讲讲背景,我们为什么要使用Handler。由于Android 是强交互的移动操作系统,用户交互必不可少,界面反馈显示需要更新UI,但如果每个线程都能随意更新UI,那么多个线程同时进行操作时,最终UI的状态是不可知的,也就是说会有线程安全问题,于是乎Android中规定:只有主线程能操作UI,因此主线程也叫UI线程。

    早期的Android 版本,界面经常会出现卡顿的现象,时不时抛应用程序无响应(ANR)异常,因为我们的UI线程可能做了一些耗时的操作,比如文件读取,网络访问等。为了使UI线程保持比较快的响应速度,耗时操作不能在主线程中进行。但很多时候执行完任务需要反馈结果到界面又需要进行UI操作,这就跟我们只有UI线程能更新UI的规定相冲突了。那么怎么来解决这个矛盾呢?

    没错,就是通过我们今天要讲的Handler消息传递机制。很多人认为Handler只是用来更新UI的,确实可以,但这么理解难免有些狭隘,我的理解是这样的:Handler是用来将任务切换到不同线程中执行的机制。

    ================================================================

一、Handler的使用

    我们日常开发中,用法通常是new 一个Handler对象,或者派生一个内部类来得到Handler,然后重写里面的handleMessage()方法,然后在子线程中拿着我们的handler.sendMessage()方法,将信息Message发送给主线程去处理,使用起来非常简单。符合我们面向对象开发的 最少知识原则。

二、Handler的原理

    其实Handler能实现这么强大的功能,离不开背后Looper, MessQueue的默默支撑。之所以是默默支持,是因为我们主线程已经帮我们做了初始化,当然有些朋友说写了那么久的Android从来没见过main方法,其实也是主线程ActivityThread中帮我们实现了。

public static void main(String[] args){
  ..
  Process.setArgV0("<pre-initialized>");
  Looper.prepareMainLooper();
  ActivityThread thread = new ActivityThread();
  thread.attch(false);
  if(sMainThreadHandler == null){
    sMainThreadHandler = thread.getHandler();
  }
  ...
  Looper.loop();
}

    主线程的消息循环开始了以后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的的启动和停止等过程。

    ActivityThread通过ApplicationThread和ActivityManagerService(AMS)进行进程间通信,AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到主线程ActivityThread中执行,这个过程就是主线程的消息循环模型。

三、Looper, MessageQueue, Message, Handler之间的关系

    Looper轮询器的构造方法如下:

private Looper(boolean quitAllowed){
  mQueue = new MessageQueue(quitAllowed);
  mThread = Thread.currentThread();
}

    Handler的构造方法如下:

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

从上面的构造方法可以看出,Handler通过Loop和消息队列MessageQueue进行一一绑定,而Looper又是通过ThreadLocal实现了线程隔离,也就是说每个线程最多只会只会得到自己的Looper。

static final ThreadLocal<Looper> dThreadLocal = new ThreadLocal<Looper>();
public static void prepare(){
  prepare(true);
}
public static void prepare(boolean quitAllowed){
  if(sThreadLocal.get() != null){
    throw new RuntimeException("Only one Looper maybe created per thread");
  }
  sThreadLocal.set(new Looper(quitAllowed));
}
public static Looper myLooper(){
  return sThreadLocal.get();
}
  调用Looper.loop()后,开始轮询,loop方法中又会调用MessageQuene中的next()方法,当有队列中有消息时,就会取出来到Looper中,通过msg.target.dispatchMessage()方法进行分发,(msg.target 即消息的发送者handler)
public void dispatchMessage(Message msg){
  if(msg.callback != null){
    handleCallback(msg);
  }else{
    if(mCallback != null){
      if(mCallback.handleMessage(msg){
        return;
      }
    }
    handleMessage(msg);
  }
}

    随后就来到我们重写的handleMessage()中来了。

    。。。

    好懊恼,部分草稿忘记保存,第一篇先到这里吧

 MessageQueue里面还有一个非常有意思的东西叫dleHandler,工作换了后面估计没机会更了,放在草稿箱也不是事,当抛砖引玉吧,开启传送门:https://mp.weixin.qq.com/s/KpeBqIEYeOzt_frANoGuSg?







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值