来自: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. raiserror的用法

    描述:raiserror :是用于抛出一个错误 第一个参数:{ msg_id | msg_str | @local_variable } msg_id:表示可以是一个sys.messages表中定义的 ...

  2. Linux之mount命令详解

    linux下挂载(mount)光盘映像文档.移动硬盘.U盘.Windows和NFS网络共享linux是个优秀的开放源码的操作系统,能够运行在大到巨型小到掌上型各类电脑系统上,随着linux系统的日渐成 ...

  3. Ubuntu下codeblocks汉化

    code::blocks是一个十分好用编辑环境,一个在手,无所不能,为了更好的支持中文,我列出了汉化的方法: 1下载中文汉化包:http://pan.baidu.com/s/1hqvNZbI 2.解压 ...

  4. 一个Java对象到底占用多大内存

    在网上搜到了一篇博客讲的非常好,里面提供的这个类也非常实用: import java.lang.instrument.Instrumentation; import java.lang.reflect ...

  5. c++各种排序

    1.插入排序 void InsertSort(int a[], int n) { int temp, i, j; ; i < n; i++) { ]) { temp = a[i]; ; j &g ...

  6. C语言中的字符串拷贝函数strcpy和内存拷贝函数memcpy的区别与实现

    strcpy和memcpy都是标准C库函数,它们有下面的特点. strcpy提供了字符串的复制.即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符'\0'. 已知st ...

  7. linux第四周作业

    一.用户态内核态与中断 1.库函数把内核调用封装起来. 2.区分内核态和用户态是为了让系统更稳定.Linux里吧用户态定位3级,把内核态定位0级. 3.中断处理就是从用户态进入内核态的主要方法,系统调 ...

  8. Notes of the scrum meeting(2013/10/20)

    软工项目组buaa_smile确定自由项目主题及实现功能的scrum meeting meeting time:7:30~9:00p.m.,October 20th,2013 meeting plac ...

  9. Sponsored Feature: Common Performance Issues in Game Programming

    转自http://www.gamasutra.com/view/feature/132084/sponsored_feature_common_.php?print=1 By Becky Heinem ...

  10. android 弹出框(输入框和选择框)

    1.输入框: final EditText inputServer = new EditText(this); inputServer.setFilters(new InputFilter[]{new ...