`
gogoalong
  • 浏览: 49678 次
  • 性别: Icon_minigender_1
  • 来自: 湖南
社区版块
存档分类
最新评论

[Android源码]Handler分析

阅读更多

一,Handler介绍

Handler:处理者。Handler的主要作用异步处理消息。主要方法是:发送消息、处理消息。当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。

二,Handler的基本用法

public class MainActivity extends Activity  
{
    private final int WHAT = 100;
    private TextView mTextTitle;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTextTitle = (TextView) findViewById(R.id.textview1);
        new Thread(runnable).start();
    }
 
    Runnable runnable = new Runnable(){
        @Override
        public void run() {
            int count = 0;
            for (int i = 0; i < 10; i++) {
                count ++;
            }
            Message msg = handler.obtainMessage();
            msg.what = WHAT;
            msg.arg1 = count;
            handler.sendMessage(msg);
        }
    };
    Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case WHAT:
                    int count = msg.arg1;
                    mTextTitle.setText("总共人数:" + count);
                break;
            }
            return false;
        }
    });
}

2.1 构造方式

上述代码中构造Handler对象使用的是

[1]Handler handler = new Handler(new Handler.Callback()){

public boolean handleMessage(Message msg){}

}

Handler也允许使用

[2]Handler handler = new Handler(){

public void handleMessage(Message msg){}

};但是使用方式[2],eclipse会出现黄色警告[This Handler class should be static or leaks might occur]大致意思是:Handler类应该定义成静态类,否则可能导致内存泄露。根据不同的应用场景,如果Handler只需要使用handleMessage(Message msg)回调方法的话,可以使用方式[1]解决掉警告提示。如果需要重写Handler的其他方法,可以使用

static Handler handler = new Handler() {

public void handleMessage(Message msg){}

};[参考]:http://www.cnblogs.com/savagemorgan/archive/2013/01/23/2872371.html

2.2 功能描述

在子线程进行长时间逻辑算法操作(for循环),将算法操作结果显示到UI界面上。

2.3 流程描述

1,开启子线程进行计算;

2,Handler 通过sendEmptyMessage(int what)将消息添加到消息循环队列中;

3,消息循环队列取出消息回调Handler.dispatchMessage()分发消息;

4,回调方法handleMessage(Message msg)来处理消息;

5,将结果显示到TextView组件

2.4 使用总结

1,有三点需要注意,[1]Message对象是使用Message msg = handler.obtainMessage();携带int基本类型参数是使用[2]msg.arg1=count;这个可以看上一篇文章[android源码分析之Message]。[3]为什么不能直接在子线程修改TextView的显示信息,可以看文章Android:CalledFromWrongThreadException

2,使用Handler的对象的引用可以在任意线程发送消息。而处理消息只在构造Handler对象的那个线程中。Handler与Activity还有消息循环队列之间的关系图。

3,通过上面介绍基本懂得如何在代码中使用Handler。

那么Handler是如何将消息发送到消息循环队列的呢?sendMessage(Message msg)之后做了哪些操作。

三,Handler分析

3.1 构造函数

    private static final boolean FIND_POTENTIAL_LEAKS = false;
    final MessageQueue mQueue;
    final Looper mLooper;
    final Callback mCallback;
    /**
     * Constructor associates this handler with the queue for the
     * current thread and takes a callback interface in which you can handle
     * messages.
     */
    public Handler(Callback callback) {
        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());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
    }

跟踪Handler源码,我们一起看看Handler的构造函数。因为FIND_POTENTIAL_LEAKS=false;所以if(FIND_POTENTIAL_LEAKS){}这段代码可以不用分析。接下来几行代码则是Handler的核心。[1]mLooper=Looper.myLooper();关联一下消息循环Looper。[2]mQueue=mLooper.mQueue;关联消息循环中的消息队列MessageQueue,作为自己的一个成员属性。Handler与消息循环以及消息队列建立联系后,Handler就可以发送消息到消息队列。

mLooper=Looper.myLooper(); :一个线程构造使用Handler,需要调用Looper.prepare(),将线程初始化成一个消息循环线程。如果在一个子线程创建Handler之前没有调用Looper.prepare()将该线程转变成消息循环线程。则会抛
Can't create handler inside thread that has not called Looper.prepare()异常。

     /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

mQueue=mLooper.mQueue;调用mQueue.enqueueMessage();将消息添加到消息队列;

3.2 常用函数

public final boolean post(Runnable r)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postDelayed(Runnable r, long delayMillis)

public final boolean sendMessage(Message msg)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendMessageDelayed(Message msg, long delayMillis
public final boolean sendMessageAtFrontOfQueue(Message msg)

3.3 消息发送

Handler允许post一个Runnable对象。Handler会将Runnable封装到Message对象中,msg.callback=runnable,之后添加将消息添加到消息队列,当消息循环队列取出此Message,直接调用Runnable的run()方法。

Handler允许send一个Message对象。Handler为开发者提供了很多封装的方法,跟踪源码,发现最后消息添加到消息队列,只有两个方法。一个是根据偏移时间[1]sendMessageAtTime,将消息插入到消息队列中。第二个方法是[2]sendMessageAtFrontOfQueue将消息添加到消息队列的头部。

下面跟踪handler.sendMessage(Message msg);

    /**
     * Pushes a message onto the end of the message queue after all pending messages
     * before the current time. It will be received in {@link #handleMessage},
     * in the thread attached to this handler.
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
  /**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

  /**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     * 
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *         
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
            msg.target = this;
            sent = queue.enqueueMessage(msg, uptimeMillis);
        }
        else {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
        }
        return sent;
    }
注:updateMillis= SystemClock.uptimeMillis() + delayMillis

跟踪代码我们可以注意到,消息发送最后到达sendMessageAtTime(Message msg, long uptimeMillis),其中uptimeMillis是当前系统闹钟时间+delayMillis是推迟发送间隔时间。

msg.target=this;将该handler引用添加到Message中,在消息循环中,通过msg.target.dispatchMessage()回调,分发消息。

queue.enqueueMessage(msg, uptimeMillis)则将消息添加进了消息队列。至此消息的发送和添加已经完成。

3.4 消息处理

当消息队列中有消息时,消息循环loop()从消息队列中取出消息

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        MessageQueue queue = me.mQueue;
        ...
        while (true) {
            Message msg = queue.next(); // might block
            if (msg != null) {
                if (msg.target == null) {
                    // No target is a magic identifier for the quit message.
                    return;
                }
                ...
                msg.target.dispatchMessage(msg);
                ...
                msg.recycle();
            }
        }
    }
Message msg = queue.next();从消息队列中取出消息,msg.target.dispatchMessage()回调Handler中的分发消息方法。

msg.recycle();将以及从消息队列中取出的消息进行回收,清空消息中存放数据,保留消息引用到消息池。

   /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {1,// 判断是否为Runnable消息
            handleCallback(msg);
        } else {
            if (mCallback != null) {2,// Handler构造为,Handler handler = new Handler(new Handler.Callback(){});
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);3,//继承Handler的子类
        }
    }
    private final void handleCallback(Message message) {
        message.callback.run();//直接调用Runnable的run() 方法
    }
消息分发根据Handler发送的消息形式,执行不同的回调。如[一,基本使用]中实现的代码方式,则是调用2,mCallback.handleMessage(msg) 。至此消息处理已经完成。
整体流程图:[引用脚本之家图片],这张图很形象的表达了消息循环的流程。

至此Handler的发送消息和处理消息流程分析完毕。


分享到:
评论

相关推荐

    android handler 机制 源码

    在这里,我们将深入探讨Android Handler机制的源码,了解其工作原理。 首先,`Handler`类是处理消息的核心组件。它通过`post()`或`sendMessage()`方法接收并分发Message对象。当创建一个Handler实例时,通常会与...

    Android源码与教程

    在Android开发领域,深入理解Android源码是提升技术能力的关键步骤。这个压缩包"Android源码与教程"包含了淘宝上购买的相关教程和一些文档源码,对于开发者来说是一份宝贵的资源。下面,我们将深入探讨Android源码的...

    安卓Android源码——HandlerLooper2.rar

    这个压缩包“安卓Android源码——HandlerLooper2.rar”可能包含了关于这些组件的深入分析和示例代码。以下是关于`Handler`、`Looper`和`MessageQueue`的详细解释: 1. **Handler**: - `Handler`是Android中的一个...

    安卓Android源码——HandlerMessage3.rar

    这个压缩包"安卓Android源码——HandlerMessage3.rar"很可能包含了关于这三者如何协同工作的示例代码或者详细分析。现在,我们将深入探讨这些概念及其在Android系统中的作用。 `Handler` 是一个用于发送和处理消息...

    进阶android源码demo

    "进阶Android源码demo"提供了一系列的实践项目,包括游戏和聊天应用,为开发者提供了丰富的学习资源。下面,我们将深入探讨这些知识点,以帮助你更好地理解和应用Android源码。 1. **Android框架理解**:Android...

    安卓Android源码——HandlerMessage2.rar

    本资源"安卓Android源码——HandlerMessage2.rar"可能包含了关于`Handler`和`Message`的深入实践和示例代码,下面我们将详细探讨这些核心组件。 `Handler` 是 Android 中用于在线程间传递消息的对象。它通常用于将...

    Android_Handler01-源码.rar

    【Android_Handler01-源码】是一个关于Android Handler机制的源码分析项目。在Android开发中,Handler、Looper和Message是实现线程间通信的重要组件,尤其在UI更新和异步任务处理上扮演着核心角色。这个源码库可能是...

    android mars视频代码 Handler 源码 ProgressBarHandler

    www.mars-droid.com/Android开发视频教程 代码 源码 mars老师讲课 android 视频源码 Handler ProgressBarHandler(在此特别感谢mars的无私奉献,此代码为跟随视频边学边做的)

    androidHandler测试的demo

    4. 源代码分析:可能包含对Android系统源码中`Handler`、`Looper`相关部分的注释和解释,帮助理解它们的工作原理。 5. 测试用例:可能有针对`Handler`功能的测试代码,验证不同线程间的通信是否正常,消息处理是否...

    安卓Android源码——HandlerLooper1.rar

    5. `Handler`与`AsyncTask`、`Runnable`、`IntentService`等其他异步处理方式的对比分析。 通过学习这部分源码和解析,开发者可以更好地理解和运用Android的消息处理机制,优化多线程编程,提高应用的性能和用户...

    Android应用源码之HandlerMessage1_HandlerMessage.zip

    总结来说,`Android应用源码之HandlerMessage1_HandlerMessage.zip`中的内容可能展示了如何利用`Handler`、`Message`和`Looper`进行多线程间的通信,以确保UI线程的流畅运行。理解和掌握这一机制对于Android开发者来...

    Android Handler消息处理顺序分析

    本文将详细分析Android Handler消息处理的顺序,以及如何利用这些组件进行异步操作。 首先,理解Handler的基本概念。Handler是Android中的一个类,用于发送和处理消息。它通常与Looper和Message配合工作,允许...

    博客园客户端android源码

    博客园客户端Android源码分析 博客园是一款深受程序员喜爱的在线技术分享平台,其客户端提供了方便的移动阅读体验。分析博客园的Android源码,我们可以深入理解如何构建一个功能完善的移动应用,特别是针对技术社区...

    开源中国android源码

    一、Android源码分析 Android源码包含了操作系统级别的组件、框架层服务、库以及应用程序接口(API)。开源中国提供的android-app-master可能是该社区Android应用客户端的源代码,它可能涵盖了以下几个关键部分: ...

    安卓Android源码——HandlerMessage1.rar

    在安卓(Android)开发中,`Handler`、`Message` 和 `Looper` 是三个非常重要的组件,它们共同构成了安卓的异步消息处理机制。这个机制是安卓系统中处理UI线程与后台线程通信的核心方式。`HandlerMessage1.rar` 文件...

    Android源代码:HandlerDemo

    在Android开发中,`Handler`是一个至关重要的组件,它用于在主线程中处理来自其他线程的消息,确保UI更新操作的正确执行。本项目“Android源代码:HandlerDemo”将深入探讨`Handler`机制及其在多线程环境中的应用。 ...

    Android应用源码之HandlerLooper2_Android.zip

    本压缩包"Android应用源码之HandlerLooper2_Android.zip"可能包含了关于这个主题的详细示例代码,让我们深入探讨这些关键组件的工作原理。 首先,`Handler`类是Android中处理消息和调度任务的核心组件。它允许...

    安卓Android源码——斗地主源码实现.zip

    这份"安卓Android源码——斗地主源码实现.zip"提供的压缩包包含了一个完整的斗地主游戏的源代码实现,其中主要的文件是"Android斗地主[牌桌实现源码].pdf"。这里我们将详细探讨这个项目中的核心知识点。 1. **...

    安卓Android源码——注释过的谷歌输入法PinyinIME源码.zip

    这份源码资源,"安卓Android源码——注释过的谷歌输入法PinyinIME源码.zip",包含了解析和注释过的谷歌输入法PinyinIME的源代码,对于开发者来说,它是一个宝贵的教育资源,可以深入理解输入法应用的内部工作原理...

    Android应用源码之HandlerMessage3_Android.zip

    通过分析这个源码,开发者能够更好地理解Android的消息处理机制,如何在子线程执行耗时操作后更新UI,以及如何避免在主线程中进行阻塞操作,提高应用性能和用户体验。 这个示例代码还可能涉及异步编程的最佳实践,...

Global site tag (gtag.js) - Google Analytics