来自: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. vs2010中安装ASP.NET AJAX Control Toolkit

    方法一: 第一步 下载Ajax Control Toolkit 进入网址http://ajaxcontroltoolkit.codeplex.com/ 即可下载 第二步 解压下载下来的Ajax Con ...

  2. WPF中的Style

    一.Style基础知识 构成Style最重要的两种元素是Setter和Trigger Setter类帮助我们设置控件的静态外观风格 Trigger类帮助我们设置控件的行为风格 Setter类的Prop ...

  3. HTTP报文格式

    请求报文 <method><SP><uri><SP><version><CRLF> <head-name><: ...

  4. mac升级yosemite后安装gd的freetype扩展

    Mac升级系统到 Yosemite 10.10,对于各位Coder来说,还是需要一些时间来折腾的! @星空之下 同学反映 PHPCMS 的验证码图片不能正常显示,反馈该验证码需要GD库支持FreeTy ...

  5. C#调用Python 脚本语言

    1. 安装IronPython http://pan.baidu.com/s/1qW4jNJ2  下载IronPython 2.7 安装下载下来的安装包 2. 创建项目 创建一个C#的Windows窗 ...

  6. 高精度计算的类(BigInteger和BigDecimal)

    这两个类 在Java中没有对应的基本类型.不过,这两个类包含的方法,提供的操作与对基本类型所能执行的操作差不多. 也就是说,能对基本类型 int float 等的操作,也同样能作用于这两个类,只不过必 ...

  7. layoutSubviews -- setNeedsLayout -- layoutIfNeeded -- 区别

    -layoutSubviews方法:这个方法,默认没有做任何事情,需要子类进行重写-setNeedsLayout方法: 标记为需要重新布局,异步调用layoutIfNeeded刷新布局,不立即刷新,但 ...

  8. 在wamp下PHP5.5安装php-redis扩展

    windows下开发用的xampp集成的环境,想装个php-redis扩展,扩展的github地址: https://github.com/nicolasff/phpredis 描述里找到window ...

  9. List<T>中Exists 和Contains的区别

    .net编码中,使用泛型List<>时,经常遇到这样的需求:新来一个Model对象,如果已有的List中没有这条数据,则把新对象Add到List中,否则不处理 判断已有的List中是否包含 ...

  10. c语言编程之栈(数组实现)

    用数组实现的顺序栈,完成了出栈入栈功能. #include"stdio.h" typedef int element; #define max 100 typedef struct ...