android 开发Handler源码剖析

Android的消息机制主要是Handler的运行机制,而讲Handler的机制,又需要和MessageQueue和Looper结合。MessageQueue中文意思是消息队列,虽说叫队列,但是其内部结构并不是队列组成的,而是采用了单链表的形式来存储消息。MessageQueue只是负责存储消息,并不处理消息(这里指消息的轮训),Looper刚好弥补了这个空缺。我在知道,Handler创建的时候,会默认为我们创建一个Looper对象,那么如何获取当前的Looper呢,这里就使用到了一个TheadLocal的概念,TheadLocal可以轻松的获取当前使用的Looper。

Handler的使用:

Handler 主要有两种用法:( 1 )调度消息和 runnable 对象,并在某一时间点执行。( 2 )依次存放分属不同线程的行为。

线程在默认的时候是没有Looper与之相关联。在线程中,我们可以通过调用prepare 方法来启动一个消息loop,调用loop方法来通知Looper来处理消息,直至结束。Looper提供了很多的静态方法来与线程、消息队列进行交互。一个线程最多允许创建一个Looper。

以下是SDK文档中介绍的在线程中使用handler的一种方法:

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关联了,那么如果我们不关联Looper的话会怎么样呢

 mRunnable = new  Runnable(){
           @Override
           public void run() {
              // TODO Auto-generated method stub
              String s = mHandler.getLooper().getThread().getName();
              Log.e("handler", s);
              mHandler.postDelayed(mRunnable, 1000);
           }};
Thread t  = new Thread(mRunnable,"thread");
        t.start();

运行结果:
ERROR/handler(1630): main,可以发现我们创建了一个名为“thread”的线程,病通过handler发送消息,我们创建的handler自动和UI线程的Looper关联上了。

那么,可不可以在主线程中定义handler,在代码中动态改变handler使之与其他线程的looper相关联呢?是可以的。

mRunnable = new  Runnable(){
              @Override
              public void run() {
                  // TODO Auto-generated method stub
                  Looper.prepare();
                  mHandler = new Handler(Looper.myLooper());
                  String s = mHandler.getLooper().getThread().getName();
                  Log.e("handler", s);
                  mHandler = new Handler(Looper.getMainLooper());
                   s = mHandler.getLooper().getThread().getName();
                  Log.e("handler", s);
              }};
    Thread t  = new Thread(mRunnable,"subthread");
            t.start();

运行结果:

ERROR/handler(4049):subthread

ERROR/handler(4049): main

不过我们Android为我们提供了一个包含Looper的Thead类,HandlerThread
 HandlerThread自带了一个Lopper,

 handlerThread=new HandlerThread("handlerThead");
        handlerThread.start();
        handler=new Handler(handlerThread.getLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                String s=handler.getLooper().getThread().getName();
                Log.d("test",s);
            }
        });

注:android认为在非线程中操作UI界面是不安全的,因此禁止在其它线程中修改UI界面。解决的方法有两种,一是通过在主线程中定义的handler更新界面,二是直接调用被修改的view的postInvalidate方法刷新单个view。

其实上面的描述是不准确的,实际上在activity第一次执行的时候,是可以在子线程直接更新主线程数据的,条件是不能执行Thread.sleep(),

原因是什么呢?

1.当刚启动Activity即onCreate里面此时onResume方法还没有执行的时候可以,因为在线程中更新UI时会调用ViewParent.invalidateChild()方法检查当前的Thread是否是UIThread,若为UIThread则可以更新(ViewParent是一个接口类,其实现是ViewRootImpl;invalidateChild()方法调用checkThread()方法来检查线程是否为主线程)。ViewRootImp是在onResume方法中初始化的,所以只要在ViewRootImpl创建之前更新UI(在onCreate方法中创建线程并执行,此时还没有初始化ViewRootImp),就可以逃避掉checkThread()的检查进而更新UI。
2.-->刚启动的时候,立即在非UI线程更新->不报错(onResume还没有执行)
--->休眠2s钟以后,更新——————>报错

最后贴上一张图

分析完了Android消息机制的流程,那么我们接下来分别理解一些重要的概念。主要从以下几个方面增强理解,Handler,MessageQueue,Looper和Threadloacal.

时间: 2024-10-12 07:29:35

android 开发Handler源码剖析的相关文章

《GDAL源码剖析与开发指南》一一1.8 GDAL帮助文档生成

1.8 GDAL帮助文档生成 GDAL源码剖析与开发指南1.8.1 Doxygen简介 Doxygen是生成C++注释文档的标准工具,也支持其他语言,如C.Objective-C.C#.PHP.Java.Python.IDL (Corba and Microsoft flavors).Fortran.VHDL.Tcl等. 我们可以通过三种方式来使用Doxygen. 1.从源文件中以HTML形式生成在线文档浏览器,或者以LATEX形式生成非在线的参考手册,也支持RTF (MS-Word).Post

《GDAL源码剖析与开发指南》一一1.7 SWIG编译

1.7 SWIG编译 GDAL源码剖析与开发指南1.7.1 SWIG简介 SWIG全称是Simplified Wrapper and Interface Generator,官方网站是http://www.swig.org/.SWIG是一个开发工具,能够将使用C或者C++编写的软件与其他各种高级编程语言进行嵌入联接.SWIG能应用于各种不同类型的语言,包括常用脚本编译语言例如Perl.PHP.Python.Tcl.Ruby.PHP等,也包括非脚本编译语言,如C#.Common Lisp (CLI

《GDAL源码剖析与开发指南》一一1.5 GDAL源码目录

1.5 GDAL源码目录 GDAL源码剖析与开发指南 下载的GDAL源代码压缩包目录如图1-2所示,使用SVN迁出的GDAL源代码目录如图1-3所示. 从图1-2和图1-3所示可以看出,不管用什么方式获取GDAL的源代码,它的目录结构都是一样的.下面我们就针对目录结构中的每个文件夹和文件作一个简单的说明(按照字母顺序). 1.5.1 文件夹说明 对于图1-3中所示的文件夹,详细说明如下. alg:该文件夹存放的是GDAL库中提供的一些算法的源代码,这些算法包括但不限于:DEM生成等高线算法,图像

《GDAL源码剖析与开发指南》一一1.6 GDAL编译

1.6 GDAL编译 GDAL源码剖析与开发指南 GDAL的编译分为三个小节,第一节是常规编译,使用微软的Visual Studio 2008进行编译,如果用微软的其他编译器,编译过程与此类似.需要注意的是,GDAL已经不再支持Visual C++6.0编译器.第二小节主要说明怎样修改GDAL的配置文件,以使GDAL支持更多的数据格式以及算法等.第三小节对编译GDAL的64位版本进行说明. 1.6.1 常规编译 1.使用Visual Studio 2008 IDE编译 在GDAL的源代码目录中,

《GDAL源码剖析与开发指南》导读

前言 GDAL源码剖析与开发指南 GDAL全称是Geospatial Data Abstraction Library(地理空间数据抽象库),是一个在X/MIT许可协议下读写空间数据(包括栅格数据和矢量数据)的开源库,它利用抽象数据模型来表达所支持的各种文件格式,还使用一系列命令行工具来进行数据转换和处理. 由于GDAL库支持很多数据格式,目前几乎所有的GIS和RS软件底层都使用GDAL来读写空间数据. 目前国内外关于GDAL的图书非常少,比较权威的只有GDAL官网的说明文档,导致用户缺少实用的

《GDAL源码剖析与开发指南》一一1.1 什么是GDAL

1.1 什么是GDAL GDAL源码剖析与开发指南 GDAL全称是Geospatial Data Abstraction Library(地理空间数据抽象库),是一个在X/MIT许可协议下读写空间数据(包括栅格数据和矢量数据)的开源库,它利用抽象数据模型来表达所支持的各种文件格式,还使用一系列命令行工具来进行数据转换和处理. OGR(OGR Simple Features Library)是GDAL项目的一个分支,功能与GDAL类似,只是它提供对矢量数据的读写支持.同时它实现了一个对空间参考信息

《GDAL源码剖析与开发指南》一一1.3 GDAL支持的数据格式

1.3 GDAL支持的数据格式 GDAL源码剖析与开发指南 GDAL支持的数据格式分为两种:栅格数据格式和矢量数据格式.GDAL在每次版本更新的时候,都会加入对新的格式的支持.本书使用GDAL1.10版本中支持的栅格数据格式,如表1-1所示,支持的矢量数据格式如表1-2所示. 注意 文件的最大存储大小不仅由文件的格式决定,而且和操作系统有关系.

《GDAL源码剖析与开发指南》一一1.4 GDAL源码下载

1.4 GDAL源码下载 GDAL源码剖析与开发指南 GDAL的源码下载有两种方式.第一种是直接下载打包好的压缩包,下载地址为:http://trac.osgeo.org/gdal/wiki/DownloadSource.另外,GDAL的各个历史版本都可以在这个地址进行下载:http://download.osgeo.org/gdal/.这种下载方式很简单,此处不作说明.下载完成,使用压缩软件解压即可. 第二种下载方式是使用SVN源代码管理工具直接从GDAL的源码服务器进行下载.下载地址是:ht

从源码剖析Android中的Intent组件_Android

我们知道,Intent主要用来激活安卓几大组件,那么它具体是怎样来激活的?激活时是否可以携带java对象?为何要将对象序列化后才能传递? 一.Intent官网解释Intent可以被startActivity用来加载Activity,也可以被broadcastIntent发送给指定的BroadReceiver组件, 或者被startService.bingService来与后台service通信. Intent最主要作用就是加载Activity,好比Activity之间的胶水. Intent数据结