Android中的消息机制主要就是指Handler的消息机制,Handler相信大家已经非常熟悉了,它可以将一个任务切换到Handler所在的线程中去执行,开发中,当我们在子线程做了一些操作后需要更新UI,由于Android不允许在子线程中访问UI控件,所以我们一般都会使用handler来实现。

Handler的机制需要MessageQueue、Looper和Message的支持。他们在消息机制中各扮演了不同的角色

Handler:负责消息的发送和接收处理
MessageQueue:消息队列,一个消息存储单位,经常需要进行增减,内部使用的是单链表的结构
Looper:消息循环。会不停地从MessageQueue中取消息,如果有新消息就会立刻处理,否则就一直阻塞在那里
Message:消息载体

下面通过一段简单的代码来分析整个执行过程。

 private TextView textView; private Handler handler = new Handler(){     @Override     public void handleMessage(Message msg) {          super.handleMessage(msg);          textView.setText("消息处理.....");     } };@Overrideprotected void onCreate(Bundle savedInstanceState){        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        textView = (TextView) findViewById(R.id.mytv);        new Thread(new Runnable() {            @Override            public void run() {                //模拟耗时操作                SystemClock.sleep(3000);                handler.sendMessage(new Message());            }        }).start();    }

就是在子线程中做了一些耗时操作后,通过Handler发送消息去更新UI

Hanlder是怎么接受到消息的呢?

Looper

Looper几个主要的方法

  • Looper.prepare():为当前线程创建一个Looper
  • Looper.loop():开启消息循环
  • Looper.getMainLoop():可以在任何地方获取到主线程的
  • Looper.quit():直接退出Looper
  • quitSafely():设置一个标记,把消息队列的所有消息处理完后才会退出
//创建一个新的Looper并放到当前线程的ThreadLocal中去 private static void prepare(boolean quitAllowed){        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper(quitAllowed));    }

再看看Looper的构造方法,发现,Looper中保存有一个MessageQueue

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

loop()该方法是一个死循环,会不断从MessageQueue中去取消息,当获取到消息后,将交由Handler去处理

public static void loop() {    //myLooper方法会从ThreadLocal中获取到当前线程的Looper    final Looper me = myLooper();    if (me == null) {        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");    }     final MessageQueue queue = me.mQueue;    Binder.clearCallingIdentity();    final long ident = Binder.clearCallingIdentity();    for (;;) {        //不断的去MessageQueue中取消息        Message msg = queue.next();        if (msg == null) {            return;        }           Printer logging = me.mLogging;        if (logging != null) {          logging.println(">>>>> Dispatching to " + msg.target + " " +                msg.callback + ": " + msg.what);    }       //调用发送该消息的Handler的dispatchMessage方法处理该消息      //这里的msg.target == Handler,是在Handler发送消息的时候进行赋值的       msg.target.dispatchMessage(msg);        if (logging != null) {            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);    }        final long newIdent = Binder.clearCallingIdentity();        if (ident != newIdent) {            Log.wtf(TAG, "Thread identity changed from 0x"                + Long.toHexString(ident) + " to 0x"                + Long.toHexString(newIdent) + " while dispatching to "                + msg.target.getClass().getName() + " "                + msg.callback + " what=" + msg.what);    }      msg.recycleUnchecked();}

Looper大概就是这么一回事,每条线程绑定一个Looper(子线程需要自己调用Loop.prepare()),保证每条线程都只有一个Looper实例
随后调用Looper.loop开启消息循环,进入堵塞状态,等待消息的到来

MessageQueue

相对来说就很简单来,就两个操作,插入和读取。可以看成一个消息容器

Handler

先来看看他的构造方法

```javapublic 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());        }    }   //获取当前线程中的Looper   mLooper = Looper.myLooper();    if (mLooper == null) {     //如果当前线程没有Looper就会抛出异常。       throw new RuntimeException(            "Can't create handler inside thread that has not called Looper.prepare()");    }    //获取Looper中的MessageQueue,可以看出,Looper中为每个线程维护了一个Message   mQueue = mLooper.mQueue;    mCallback = callback;   mAsynchronous = async;}

接来下看看Handler发送消息的方法,追踪senndmessage到最底层的方法就是enqueueMessage。

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

主要做了两个操作
msg.target = this;将发送的Message的target指向当前Handler。
ueue.enqueueMessage(msg, uptimeMillis);往当前线程的MessageQueue插入一条消息

前面在Looper.looper()方法中我们看到msg.target.dispatchMessage(msg); 获取到消息后,调用Handler的dispatchMessage方法进行消息处理。

public void dispatchMessage(Message msg) {    if (msg.callback != null) {        handleCallback(msg);//这里是Message的Callback,也就是开启我们在postDelayed传入的Runnable    } else {      //mCallback:构造器传入的实现        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                   return;            }        }      //handler自己的handler,一般由派生之类来实现        handleMessage(msg);    }}

可以看到Handler最终将调用handlerMessage处理消息,当然这里的handlerMessage处理是有优先级的

下面我们总结下流程
流程总结:
1,首先调用Looper.prepare()方法,会创建一个Looper实例,该实例包含一个MessageQueue,并将该实例保存在当前线程中Threadlocal
2,调用Looper.loop()开始消息循环,不断地向MessageQueue中读取消息,并调用msg.target.dispatchMessage(msg);来处理消息
3,构建Handler的时候,会先获取到当前Handler所在线程的Looper并得到其中的 MessageQueue
4,使用Handler发送消息的时候,会将一个Message到保存当前线程Looper中的MessageQueue
5,当Looper.loop()获取到消息的时候,调用msg.target.dispatchMessage(msg)来处理消息,其实Message.target = handler。也就是调用Handler的dispatchMessage来处理
6,Handler的dispatchMessage最终回去调用handlerMessage方法。到这里就知道,其实Handler的handler在哪条线程执行,取决于构建Handler时所使用的是哪条线程保存的Looper,因为handlerMessage其实是Looper去调用的。

下面通过一张图来表述下具体流程


这里写图片描述

前面说到,Handler必须有Looper才能执行,或者会就抛出异常,当前我们在日常使用中,直接在Activity中定义Handler就可以用啦,并没有说调用Looper.prepare来进行初始化操作。

其实UI线程默认已经做了这些操作了。对于我们来说是隐形的

大家都知道Android的程序入口是ActivityThread类,他有个main方法,我们看看他做了什么

 public static void main(String[] args) {        //省略。。。。        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        AsyncTask.init();        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

可以看到main方法主要就是消息循环,当main方法结束了,你的程序也就退出了

可能有人会问?UI线程已经做了Looper.loop()了?loop不是一个死循环堵塞状态吗?为什么我们程序还能跑起来。

既然main方法只是做了消息循环,那么我们Activity的生命周期的方法是怎么执行的呢?
在ActivityThread中有个Handler,Activity的生命周期方法在里面均有case,也就说是我们的代码其实就是在这个循环里面去执行的,自然不会阻塞了

当前我还有个疑惑。程序是在哪给ActivityThread的Handler发消息的呢?这个我暂时还不清楚。。还得继续学习啊。

UI线程已经帮我们做了这些工作了,但是如果我们自己new Thread的话,需要在子线程中使用Handler的话,还是要自己来实现的。
对此,Android也为我们提供了一个HandlerThread类,方便我们快速的实现需求。
HandlerThread继承了Thread

public class HandlerThread extends Thread

代码相当简单,
看看run方法

 @Override    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }

如果对前面的Handler机制理解了话,这里是不是一目了然了呢?

更多相关文章

  1. 【Android(安卓)Training - 05】与其他Apps进行交互 [ Lesson 2
  2. Android设置应用程序默认语言
  3. android handler 的removeMessages的使用
  4. android Handler机制源码详解
  5. JNI 数据类型转换
  6. Android中有关Handler的使用详解
  7. 开机自动运行程序【Android】
  8. Android异步任务和消息机制
  9. android之存储篇——SQLite数据库

随机推荐

  1. MVP 笔记
  2. Android平台软件体系浅注
  3. Android菜鸟日记12 Gallery
  4. Android中常用基本控件的使用方法和步骤(.
  5. android——彻底关闭——应用程序
  6. JavaEye Android(安卓)client 收藏管理功
  7. Android入门一(View和Button)
  8. Android文档阅读05—Hello, Android!及调
  9. Android:充电状态、轮询、电池状态、Noti
  10. android横竖屏总结