来自:http://blog.csdn.net/andyhuabing/article/details/7368217

Windows编程的朋友可能知道Windows程序是消息驱动的,并且有全局的消息循环系统。而Android应用程序也是消息驱动的,按道理来说也应该提供消息循环机制。Android通过Looper、Handler来实现消息循环机制,Android消息循环是针对线程的(每个线程都可以有自己的消息队列和消息循环)。

在 Android 系统 ,这些工作由由由Looper 及 Handler 来完成。

先分析Looper类:
主要提供负责线程的消息循环和消息队列

class LooperThread extends Thread {
        public Handler mHandler;
        
        public void run() {
            Looper.prepare();  // 准备。。。
            
            mHandler = new Handler() {
                public void handleMessage(Message msg) {  // 消息处理
                    // process incoming messages here
                }
            };
            
            Looper.loop();  // 进入消息循环
        }
    }

下面Looper类的准备函数:
private static final ThreadLocal sThreadLocal = new ThreadLocal();

public static final void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

这里利用 ThreadLocal 线程局部存储变量将将Looper与调用线程关联起来。
而消息处理流程如何呢?
    /**
     *  Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static final void loop() {
        Looper me = myLooper();  // 线程中存储的Looper对象
        MessageQueue queue = me.mQueue;  // Looper类中的消息队列
        while (true) {
            Message msg = queue.next(); // might block   获取消息
            //if (!me.mRun) {
            //    break;
            //}
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                if (me.mLogging!= null) me.mLogging.println(
                        ">>>>> Dispatching to " + msg.target + " "
                        + msg.callback + ": " + msg.what
                        );
                msg.target.dispatchMessage(msg);  // 利用 Target 注册的方法处理消息
                if (me.mLogging!= null) me.mLogging.println(
                        "<<<<< Finished to    " + msg.target + " "
                        + msg.callback);
                msg.recycle(); 
            }
        }
    }
    
可以通过Loop.myLooper()得到当前线程的Looper对象,通过Loop.getMainLooper()可以获得当前进程的主线程的Looper对象。

在android系统,UI线程就是消息的主线程,在 ActivityThread.java 中创建:
public static final void main(String[] args) {
     Looper.prepareMainLooper();
     
     Looper.loop(); //消息循环处理
}

-->
    public static final void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        if (Process.supportsProcesses()) {
            myLooper().mQueue.mQuitAllowed = false;
        }
    }

private synchronized static void setMainLooper(Looper looper) {
        mMainLooper = looper;
    }
    
再来分析 Handler 类:
主要提供负责将消息加入到特定的Looper消息队列中,并分发和处理访消息队列中的消息,构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建。

请看如下代码即可明白:
    public Handler(Looper looper, Callback callback) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
    }
    
这里也同时告诉我们将消息放入到主线程的消息队列中,只需要创建Hanlde对象时以主线程的Looper创建即可。则sendMessage及handleMessage都会在主线程中进行处理。

再看如下变量:
    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;

这里也有 队列,Looper对象及回调函数类,通过 Handler 不同构造函数完成相应的操作。
简化使用队列及消息传递的复杂性,提供方便的调用方法。其中最重要的函数是:

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);  // 1、利用 Calback 函数处理消息
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) { // 2、利用mCallback处理消息
                    return;
                }
            }
            handleMessage(msg); // 3、利用子类处理消息,这里最常用的方法,直接重载handleMessage函数
        }
    }
    
那么这几者的关系是怎么样的呢?

一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在主线程中处理了。

还有一个问题就是Looper和Handler的同步关系如何处理,在android由HandlerThread类进行解决了。

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait(); // 如果新线程还未创建Looper对象,则等待
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

新线程创建运行run函数创建Looper对象:
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();// 这里会创建程的Looper对象
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll(); // ok,创建好了则通知,最后调用Looper.loop()进入消息循环
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

这里利用 notifyAll / wait 轻检解决此问题了,所以多多使用用HanlderThread类完成多线程同步问题吧。

培训时学员提出的疑问进行补充说明:

每个线程都可以有自己的消息队列和消息循环,一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。
   
那么除了UI thread(ActivityThread main Looper线程)工作如何运行的呢?
可以参考下 AsyncQueryHandler.java 实现:

private static Looper sLooper = null;

private Handler mWorkerThreadHandler;

// 工作线程,处理消息,减轻UI thread负担
    protected class WorkerHandler extends Handler {
      public WorkerHandler(Looper looper) {
           super(looper);
      }    
    @Override
    public void handleMessage(Message msg) {
    ...
    }
    }
    
    //1、构造Looper消息处理线程HandlerThread
    public AsyncQueryHandler(ContentResolver cr) {
        super();
        mResolver = new WeakReference<ContentResolver>(cr);
        synchronized (AsyncQueryHandler.class) {
            if (sLooper == null) {
                HandlerThread thread = new HandlerThread("AsyncQueryWorker");

// 这里将会调用到HandlerThread.run()进入到Looper.loop();循环消息处理中

thread.start();

//2、利用thread.getLooper()获取自已的Looper

sLooper = thread.getLooper();
            }
        }
        //3、并设定给WorkerHandler进行构造绑定其Looper对象
        mWorkerThreadHandler = createHandler(sLooper);
    }

protected Handler createHandler(Looper looper) {
        return new WorkerHandler(looper);
    }
    
    //4 利用mWorkerThreadHandler(Handler对象)发送消息
    public void startQuery(int token,...){

Message msg = mWorkerThreadHandler.obtainMessage(token);

msg.arg1 = EVENT_ARG_QUERY;

...

msg.obj = args;

mWorkerThreadHandler.sendMessage(msg);

}

内容补充:

Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。

Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。

消息队列(MessageQueue)和消息循环(Looper),但是我们看到每个消息处理的地方都有Handler的存在,它是做什么的呢?

Handler的作用是把消息加入特定的Looper所管理的消息队列中,并分发和处理该消息队列中的消息。

构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper对象创建。

多个子线程访问主线程的Handler对象,Handler对象管理的Looper对象是线程安全的,不管是添加消息到消息队列还是从消息队列中读取消息都是同步保护的,所以不会出现数据不一致现象。

转 Android的消息处理机制的更多相关文章

  1. 转 Android的消息处理机制(图+源码分析)——Looper,Handler,Message

    作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想.android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种 ...

  2. 【转】android的消息处理机制(图+源码分析)——Looper,Handler,Message

    原文地址:http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html#!comments 作为一个大三的预备程序员,我学习 ...

  3. android的消息处理机制(图+源码分析)——Looper,Handler,Message

    android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种helper类,对于和我一样渴望水平得到进阶的人来说,都太值得一读了.这不,前几天为了了解android ...

  4. 《Android进阶》之第三篇 深入理解android的消息处理机制

    Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系 android的消息处理机制(图+源码分析)——Looper,Handler,Message an ...

  5. Android异步消息处理机制(多线程)

    当我们需要执行一些耗时操作,比如说发起一条网络请求时,考虑到网速等其他原因,服务器未必会立刻响应我们的请求,如果不将这类操作放在子线程里去执行,就会导致主线程被阻塞住,从而影响用户对软件的正常使用. ...

  6. 【转载】Android异步消息处理机制详解及源码分析

    PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...

  7. android的消息处理机制——Looper,Handler,Message

    在开始讨论android的消息处理机制前,先来谈谈一些基本相关的术语. 通信的同步(Synchronous):指向客户端发送请求后,必须要在服务端有回应后客户端才继续发送其它的请求,所以这时所有请求将 ...

  8. Android异步消息处理机制

    安卓子线程无法直接更改UI,所以需要异步消息处理机制来解决 <?xml version="1.0" encoding="utf-8"?><Li ...

  9. android基础(六)android的消息处理机制

    Android中的消息处理机制由四个部分组成:Message.Handler.MessageQueue和Looper,并且MessageQueue封装在Looper中,我们一般不直接与MQ打交道. 一 ...

  10. Android 异步消息处理机制解析

    Android 中的异步消息处理主要由四个部分组成,Message.Handler.MessageQueue.Looper.下面将会对这四个部分进行一下简要的介绍. 1. Message: Messa ...

随机推荐

  1. Jackson怎样转换这样的字符串? String jsonStr = "{dataType:'Custom',regexp:'t\\d+',msg:'输入不正确'}";

    字符串 String jsonStr = "{dataType:'Custom',regexp:'t\\d+',msg:'输入不正确'}"; 实体 package com.asia ...

  2. c++各种数据类型表示范围

    符号属性     长度属性     基本型     所占位数     取值范围       输入符举例      输出符举例 --            --          char        ...

  3. ORA-15221: ASM operation requires compatible.asm of 11.2.0.0.0 or higher

    昨天在做存储迁移的时候,对ASM磁盘组的东西进行操作时,出现了如标题的错误.经查资料,发现原因如下:     如磁盘组是使用asmca图形化工具创建,则compatible.asm默认设置就已经为11 ...

  4. Net Core开源通讯组件 SmartRoute

    Net Core开源通讯组件 SmartRoute(服务即集群) SmartRoute是基于Dotnet Core设计的可运行在linux和windows下的服务通讯组件,其设计理念是去中心化和零配置 ...

  5. angular入门系列教程2

    主题: 本篇主要介绍下angular里的一些概念,并且在咱们的小应用上加上点料.. 概念(大概了解即可,代码中遇到的会有详细注释): 模板:动态模板,是动态的,直接去处理DOM的,而不是通过处理字符串 ...

  6. JQuery绑定和注销事件

    $('#action_list > li').each(function(){ $(this).unbind('click') .bind('click', function(){ /** so ...

  7. PHP之implode与explode函数讲解

    implode (PHP 4, PHP 5) implode — 将一个一维数组的值转化为字符串 说明¶ string implode ( string $glue , array $pieces ) ...

  8. 【好玩的应用】QQ连连看辅助工具

    自己学了这么久的C语言,但没有写出过什么可以用的东西来,总觉得心里不爽.这几天实在是不想干正事,在网上瞎逛逛,结果发现有人写了连连看的外挂.顿时觉得这很有意思啊.于是把代码下载下来,捣鼓了捣鼓.发现还 ...

  9. sql 判断两个时间段是否有交集

    本文转自CSDN 链接地址:http://blog.csdn.net/dasihg/article/details/8450195 时间段:starttime_1到endtime_1,starttim ...

  10. ios 沙盒 NSCoding(相当于JAVA对象序列化) 归档 数据存储

    通过NSCoding能实现像JAVA一样能够实现对象的序列化,可以保存对象到文件里. NSCoding 跟其他存储方式略有不同,他可以存储对象 对象存储的条件是: 对象需要遵守 NSCoding 协议 ...