前言

  如果你在阅读本文之前,你不知道Handler在Android中为何物,我建议你先看看本系列的第一篇博文《Android:异步处理之Handler+Thread的应用(一)》;我们都知道在Android系统中不能在子线程中直接更新UI界面,所以我们一般借助Handler+Thread或者AsyncTask这两种方法来实现UI界面的更新。而Handler+Thread这方法其实就是子线程向UI主线程进行消息传递,通知UI主线程去更新界面的一套机制。因为有时候面试官比较喜欢和蔼可亲的考你Handler的这套机制,所以我们结合源代码深入的研究这套通讯机制是灰常有必要的,你想想如果能鄙视一下面试官,呵呵o(╯□╰)o。。

概述

  谷歌的这套消息机制是参考windows设计的,姑爷微爷之间有啥专利官司咱也不关心。一般来说,线程都会通过Looper来建立自己的消息循环,并且锁定一个FIFO的消息队列MessageQueue,Handler通过Looper来实现Message(消息)在MessageQueue中的存取。每一个Hanlder在实例化的时候都会自动或者手动绑定一个Looper,间接向一个MessageQueue发送Message,所以Handler也封装了消息发送和接收的接口。

入门例子

  看概述好闷的,琢磨文字不说,晦涩又难懂,记得住又成一个大问题。来不如来个例子瞧瞧比较实在,所以我在这里给大家写了一个向子线程发送消息并显示输出的例子,强调一下下哦,是向子线程哟。

主要代码如下:

public class MainActivity extends ActionBarActivity {    private Handler handler;    private Button btn;        @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                btn = (Button) findViewById(R.id.sendmsg);                new HandlerThread().start();//启动子线程                btn.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                handler.sendEmptyMessage(0);//向子线程发送消息            }        });    }    class HandlerThread extends Thread{        @Override        public void run() {            //开始建立消息循环            Looper.prepare();//初始化Looper            handler = new Handler(){//默认绑定本线程的Looper                @Override                public void handleMessage(Message msg) {                    switch(msg.what){                    case 0:                        Toast.makeText(MainActivity.this, "子线程收到消息", Toast.LENGTH_SHORT).show();                    }                }            };            Looper.loop();//启动消息循环        }    }}

布局文件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <Button        android:id="@+id/sendmsg"         android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="向子线程放炮!"        />    </LinearLayout>

我们只需要点击按钮,发送成功。。。。。

我在里简单说一下消息发送的过程:

1、启动一个子线程,并在子线程初始化一个Looper。

2、在HandlerThread中实例化Handler,Handler自动绑定上当前线程的Looper。

3、重写Handler里面的消息处理方法。

4、执行Looper.loop()启动消息循环,子线程进入等待消息状态。

做个小研究

  当然,由例子入手讲解才容易理解。我们就通过上面梳理好的消息发送流程,结合源代码来探究消息循环的建立、消息的分发和处理的原理。

1、Looper的初始化

我们进入Looper中查看源码:

public static void prepare() {  prepare(true);}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的prepare这个静态方法的时候,我们发现这个线程创建了一个Looper实例,并将其赋值给sThreadLocal这个线程的局部变量中,当然我们可以肯定这个sThreadLocal是当前的线程私有的,不信自己度娘去。我们接下来就要看Looper的构造方法。

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

相信大家的眼睛都是雪亮的吧?!在Looper()中,实例化了一个消息队列(MessageQueue)!并且如我们所愿的绑定到了mQueue这个局部变量上,在这里我们可以得出这么一个结论:调用Looper. prepare()的线程就建立起一个消息循环的对象,但是!并还没有开始展开消息循环这件大事件。

2、实例化Handler并绑定当前线程的Looper

我们可以看看Handler的源代码——Handler的构造方法

public Handler() {  this(null, false);}public 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());    }  }  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;  mAsynchronous = async;}

在代码中我们通过handler = new Handler() 调用到了Handler(Callback callback, boolean async)这个方法;我们发现mLooper = Looper.myLooper()把线程中的Looper绑定到了Handler上,通过mQueue = mLooper.mQueue获取了线程的消息队列,我当然也可以换句话说:Handler已经绑定到了创建此Handler对象的线程的消息队列上了,所以咱们可以开始干坏事了。。。。

3、重写Handler的handleMessage()方法

public void handleMessage(Message msg) {}

没啥好说的,一个空方法而已,提供我们override的入口函数。

4、通过Looper.loop()启动消息循环

还是上面的思路,我们进入loop()里面看看,总会有收获的。。

public static void loop() {  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 (;;) {    Message msg = queue.next(); // might block    if (msg == null) {      return;    }    Printer logging = me.mLogging;
    if (logging != null) {      logging.println(">>>>> Dispatching to " + msg.target + " " +        msg.callback + ": " + msg.what);    }    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.recycle();
  }}

  在loop()的这个静态方法中,我们可以注意到for (;;)这个方法,这是死胡同死循环,所以我们将其称作为“消息循环”,说起来挺形象滴。在消息循环中会调用queue.next()来获取消息队列中排队等待处理的消息,并将其赋值到msg这个变量上;接下来就判断如果msg != null 就开始分发消息,也就是执行msg.target.dispatchMessage(msg)。在分发消息结束后,将会回收掉这个消息,体现在msg.recycle()这个函数上。

msg.target是一个handler对象,表示需要处理这个消息的handler对象,所以我们回到Handler看看dispatchMessage()这个方法了:

public void dispatchMessage(Message msg) {  if (msg.callback != null) {    handleCallback(msg);  } else {    if (mCallback != null) {      if (mCallback.handleMessage(msg)) {        return;      }    }    handleMessage(msg);  }}

  不知道大家有没有一眼发现handleMessage()这个方法,这可不是我们在第三步重写Handler中的方法么。真相大白,当 msg.callback != null 并且mCallback != null 时将会调用handleMessage(msg) 来处理其他线程发送来的消息,我们通过覆盖这个方法来实现我们具体的消息处理过程;这也就是Handler消息处理机制的全部内容。

做个小结吧

  通读全文,我们可以知道消息循环机制的核心就是Looper,因为Looper持有了MessageQueue的对象,并且可以被一个线程设为该线程的一个局部变量,我们可以这么认为这个线程通过Looper拥有了一个消息队列。而Handler的用处就是封装了消息发送和消息处理的方法,在线程通信中,线程可以通过Handler发送消息给创建Handler的线程,通过Looper将消息放入进入消息接收线程的消息队列,等待Looper取出消息并在最后交给Handler处理具体消息。

再说一句

  我们会发现在Activity中实例化一个Handler并不需要Looper.prepare()来初始化一个Looper和Looper.loop()来启动消息循环,因为Activity在构造过程中已经对Looper进行了初始化并且建立了消息循环,参见ActivityThread.java中的代码:

public final class ActivityThread {    public static final void main(String[] args) {        ......        Looper.prepareMainLooper();        ......        ActivityThread thread = new ActivityThread();        thread.attach(false);        ......        Looper.loop();        ......        thread.detach();        ......    }}

  Android应用程序进程在启动的时候,会在进程中加载ActivityThread类,并且执行这个类的main函数,应用程序的消息循环过程就是在这个main函数里面实现的;如果大家想要更深入了解的话,建议大家去研究下Activity的启动机制哈。

作者:enjoy风铃
出处:http://www.cnblogs.com/net168/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则下次不给你转载了。

更多相关文章

  1. 【起航计划 013】2015 起航计划 Android(安卓)APIDemo的魔鬼步伐
  2. Android(安卓)之 Choreographer 详细分析
  3. 【Android】实现登录、注册、数据库操作(极复杂)
  4. android中的ANR
  5. 服务器主动向android手机端推送消息---------Linux下实现
  6. 【Android】点击WebView中的按钮,关闭当前activity
  7. Android(安卓)SQLite数据库增删改查操作的使用
  8. android 自定义view 前的基础知识
  9. Android有四大组件

随机推荐

  1. Android开发秘籍学习笔记(三)
  2. Android中关于FTP的文件上传和下载
  3. android发送模拟按键消息,出现死锁,timeout
  4. android学习和广告平台赚钱
  5. Android Studio编译release版本
  6. android 的消息处理
  7. Android截屏实现——亲测有效代码
  8. 转自 老罗 Android应用程序资源管理器(Ass
  9. Android Duplicate files copied in APK
  10. android 模拟抢红包 原理