Android Handler

来源:互联网 发布:淘宝宝贝搜索不到 编辑:程序博客网 时间:2024/05/17 09:33

Android Handler

参考
Android消息机制1-Handler(Java层)
Android异步消息处理机制完全解析,带你从源码的角度彻底理解

对于线程是一段可以执行线程内部的代码,当可执行的代码执行完毕 当前线程的生命周期就终止,线程退出
对于主线程绝对不希望自己就退出 需要他一直处于可执行的状态 ———————— 死循环 既可以最方便解决这个方案
真正会导致主线程出现ANR的 既是onCreate,onStrat()等方法执行时间过长导致出现的


这样就达到子线程可以唤醒UI线程(主线程),而且主线程不会因为是死循环的原因一直抢夺CPU的执行权 浪费CPU资源

  • Handler机制原理分析

界面绘制与更新只能在UI线程中操作 如果子线程想要更新UI界面需要使用Hnadler机制
使用Handler机制需要使用到Hnadler,Looper,MessageQueen这三个对象


异步操作标准写法

    class LooperThread extends Thread {      public Handler mHandler;//全局Hanler 方便其他线程引用到这个对象      public void run() {          Looper.prepare();//创建Looper对象 所有的Handler操作都需要Looper对象          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // 获取到其他线程发来的Mesage消息              }          };          Looper.loop();//死循环遍历消息      }    }

其他线程发送消息到上面线程上

    handler.sendMessage(Message msg);    handler.sendxxxx

这些方法最后都会调用到

    参数1:Mesage信息    参数2:发送时间    public boolean sendMessageAtTime(Message msg, long uptimeMillis)      {          boolean sent = false;          MessageQueue queue = mQueue;//消息队列          if (queue != null) {              msg.target = this;              sent = queue.enqueueMessage(msg, uptimeMillis);//Message信息入队列         }          else {              RuntimeException e = new RuntimeException(                  this + " sendMessageAtTime() called with no mQueue");              Log.w("Looper", e.getMessage(), e);          }          return sent;      }  
  • Looper.prepare()
    每个子线程只可以创建一个looper对象 如果在TSL区域中有looper对象 将会抛出异常
    private static void prepare(boolean quitAllowed) {    //每个线程只允许执行一次该方法,第二次执行时线程的TLS已有数据,则会抛出异常。    if (sThreadLocal.get() != null) {         throw new RuntimeException("Only one Looper may be created per thread");    }    //创建Looper对象,并保存到当前线程的TLS区域    sThreadLocal.set(new Looper(quitAllowed));   }

ThreadLocal: 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。TLS常用的操作方法:

ThreadLocal.set(T value):将value存储到当前线程的TLS区域,源码如下:

    public void set(T value) {      Thread currentThread = Thread.currentThread(); //获取当前线程      Values values = values(currentThread); //查找当前线程的本地储存区      if (values == null) {          //当线程本地存储区,尚未存储该线程相关信息时,则创建Values对象          values = initializeValues(currentThread);       }      //保存数据value到当前线程this      values.put(this, value);  }

ThreadLocal.get():获取当前线程TLS区域的数据,源码如下:

    public T get() {      Thread currentThread = Thread.currentThread(); //获取当前线程      Values values = values(currentThread); //查找当前线程的本地储存区      if (values != null) {          Object[] table = values.table;          int index = hash & values.mask;          if (this.reference == table[index]) {              return (T) table[index + 1]; //返回当前线程储存区中的数据          }      } else {          //创建Values对象          values = initializeValues(currentThread);      }      return (T) values.getAfterMiss(this); //从目标线程存储区没有查询是则返回null  }

ThreadLocal的get()和set()方法操作的类型都是泛型,接着回到前面提到的sThreadLocal变量,其定义如下:

static final ThreadLocal sThreadLocal = new ThreadLocal()
可见sThreadLocal的get()和set()操作的类型都是Looper类型> 把Looper存储到线程TSL中 方便之后取出Looper对象 Looper构造函数中创建当前线程唯一的MessageQueen对象* 入队
    参数1:Mesage信息    参数2:发送时间    final boolean enqueueMessage(Message msg, long when) {        if (msg.when != 0) {            throw new AndroidRuntimeException(msg + " This message is already in use.");        }        if (msg.target == null && !mQuitAllowed) {            throw new RuntimeException("Main thread not allowed to quit");        }        synchronized (this) {            if (mQuiting) {                RuntimeException e = new RuntimeException(msg.target + " sending message to a Handler on a dead thread");                Log.w("MessageQueue", e.getMessage(), e);                return false;            } else if (msg.target == null) {                mQuiting = true;            }            msg.when = when;            Message p = mMessages;            if (p == null || when == 0 || when 

总结

这里写图片描述

  • Handler通过sendMessage()发送Message到MessageQueue队列;
  • Looper通过loop(),不断提取出达到触发条件的Message,并将Message交给target来处理;
  • 经过dispatchMessage()后,交回给Handler的handleMessage()来进行相应地处理。
  • 将Message加入MessageQueue时,处往管道写入字符,可以会唤醒loop线程;如果MessageQueue中没有Message,并处于Idle状态,则会执行IdelHandler接口中的方法,往往用于做一些清理性地工作。



这样就做到子线程可以操控主线程更新UI

上诉的论述中可知 主线程是处于死循环中 因为这样就可以避免主线程退出 可以大胆推测出整个App进程中操作UI线程中采用Handler机制 获取来自其他线程的消息 然后使UI线程做出相对应的消息

  • 论证

    ActivityThread的内部类H继承于Handler,通过handler消息机制 从其他子线程中获取Message消息 解析Mesage消息 常用的有Activity的生命周期的调度 比如收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()方法,最终会通过反射机制,创建Activity实例,然后再执行Activity.onCreate()等方法;
    再比如收到msg=H.PAUSE_ACTIVITY,则调用ActivityThread.handlePauseActivity()方法,最终会执行Activity.onPause()等方法

但是谁发送这些Message消息给主线程的队列中?




IPC机制一般都运用到C/S架构上

system_server进程是系统进程,java framework框架的核心载体,里面运行了大量的系统服务,比如这里提供ApplicationThreadProxy(简称ATP),ActivityManagerService(简称AMS),这个两个服务都运行在system_server进程的不同线程中,由于ATP和AMS都是基于IBinder接口,都是binder线程,binder线程的创建与销毁都是由binder驱动来决定的。

ActivityManagerService 活动管理者服务 用来管控Activity的生命周期的调度和创建 但是他是在System_service进程中 需要通过ATP来通过 Binder方式传递信息到当前需要调度Activity的App进程中上的ApplicationThread上 在ApplicationThread通过Hnadler机制唤醒主线程 主线程的hanlerMessage(Message msg)方法上解析出操作的请求 做出对应的操作 完成一次生命周期的调度

1 0
原创粉丝点击