android 开发Handler源码剖析
Android的消息机制主要是Handler的运行机制,而讲Handler的机制,又需要和MessageQueue和Looper结合。MessageQueue中文意思是消息队列,虽说叫队列,但是其内部结构并不是队列组成的,而是采用了单链表的形式来存储消息。MessageQueue只是负责存储消息,并不处理消息(这里指消息的轮训),Looper刚好弥补了这个空缺。我在知道,Handler创建的时候,会默认为我们创建一个Looper对象,那么如何获取当前的Looper呢,这里就使用到了一个TheadLocal的概念,TheadLocal可以轻松的获取当前使用的Looper。
Handler的使用:
Handler )依次存放分属不同线程的行为。
线程在默认的时候是没有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.
android 开发Handler源码剖析的更多相关文章
- Android之Handler源码深入分析
闲着没事,就来看看源码,看看源码的各种原理,会用只是简单的,知道为什么才是最牛逼的. Handler源码分析那,从使用的步骤来边用边分析: 1.创建一个Handler对象:new Handler(ge ...
- Python开发【源码剖析】 List对象
前言 本文探讨的Python版本为2.7.16,可从官网上下载,把压缩包Python-2.7.16.tgz解压到本地即可 需要基本C语言的知识(要看的懂) PyListObject对象 PyListO ...
- Android开发之源码:多次点击事件的原理和实现
多次点击事件 多次点击事件原理:最后一次点击事件与第一次点击事件的时间间隔是否小于某个时间,当小于的时候,就认为这是一个多次点击事件. Android源码实现效果: import android.ap ...
- Android开发Settings源码分析之主界面加载(二)
现在都说互联网寒冬,其实只要自身技术能力够强,咱们就不怕!我这边专门针对Android开发工程师整理了一套[Android进阶学习视频].[全套Android面试秘籍].[Android知识点PDF] ...
- Python开发【源码剖析】 Dict对象
static void ShowDictObject(PyDictObject* dictObject) { PyDictEntry* entry = dictObject->ma_table; ...
- 玩转Android之Picasso使用详详详详详详解,从入门到源码剖析!!!!
Picasso是Squareup公司出的一款图片加载框架,能够解决我们在Android开发中加载图片时遇到的诸多问题,比如OOM,图片错位等,问题主要集中在加载图片列表时,因为单张图片加载谁都会写.如 ...
- Android源码剖析之Framework层升级版(窗口、系统启动)
本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 看本篇文章之前,建议先查看: Android源码剖析之Framework层基础版 前面讲了frame ...
- Android应用安全开发之源码安全
Android应用安全开发之源码安全 gh0stbo · 2016/01/21 10:24 0x00 简介 Android apk很容易通过逆向工程进行反编译,从而是其代码完全暴露给攻击者,使apk面 ...
- 第一部分:开发前的准备-第八章 Android SDK与源码下载
第8章 Android SDK与源码下载 如果你是新下载的SDK,请阅读一下步骤了解如何设置SDK.如果你已经下载使用过SDK,那么你应该使用AVD Manager,来更新即可. 下面是构建Andro ...
随机推荐
- Visual Studio 写自己的动态链接库(DLL)
有些时候,我们想写自己的函数库以避免重复写代码,此文介绍如何使用Visual Studio编写自己的动态链接库. 0,实验环境说明: 集成开发环境:Visual Studio 10.0 操作系统: W ...
- Android 6.0出现的init: cannot execve(‘XXX’):Permission denied问题:禁止SELINUX的权限设置
最近在开发MTK的相关项目,需要将一些可执行文件添加到init.rc文件里去,但是开机后发现,这个bin文件没有权限不能执行,于是我就在init.rc中对相应的bin文件增加了权限.后来发现,改了也没 ...
- Servlet规范总结
Servlet接口 Servlet规范的核心接口即是Servlet接口,它是所有Servlet类必须实现的接口,在Java Servelt API中已经提供了两个抽象类方便开发者实现Servlet类, ...
- Java基本语法-----java流程控制语句
1顺序语句 语句:使用分号分隔的代码称作为一个语句. 注意:没有写任何代码只是一个分号的时候,也是一条语句,称作空语句. 顺序语句就是按照从上往下的顺序执行的语句. 2判断(if-else) 在我们找 ...
- Android简易实战教程--第二十一话《内容观察者监听数据库变化》
当数据库的数据发生改变,我们又想知道具体改变的情况时,就需要对数据库的变化情况做一个监控.这个任务,就由内容观察者来完成.下面这个案例,为短信数据库注册内容观察者,来监控短信的变化情况,当短信数据库发 ...
- EBS销售(OE)模块常用表
select * from ra_customers 客户 select * from ra_addresses_all 地址 select * from ra_site_uses_all 用户 ...
- Android中Socket通信之TCP与UDP传输原理
一.Socket通信简介 Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信.两者的最大差异在于,http连接使用的是"请求-响应方式",即在请求时 ...
- T-SQL中的APPLY用法(半翻译)
本文接上文:T-SQL 中的CROSS JOIN用法(半翻译) 同样可用于微软认证70-461: Querying Microsoft SQL Server 2012考试的学习中. --------- ...
- 17 ContentProvider
1 Loader 转载器 Android3.0以后出来的 它可以使Activity和Fragment 异步加载数据 变得简单(Loader里封装了AsyncTask) 2 Loader特点: 对每一个 ...
- Intent和PendingIntent的区别
intent英文意思是意图,pending表示即将发生或来临的事情. PendingIntent这个类用于处理即将发生的事情.比如在通知Notification中用于跳转页面,但不是马上跳转. I ...