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 ...
随机推荐
- Zookeeper的安装配置及基本开发
一.简介 Zookeeper 是分布式服务框架,主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集群管理.分布式应用配置项的管理等等. ZooKeeper的目标就 ...
- 如何将一个二进制的xxx.bin文件轻松转为C语言数组
今天在写一个SPI-flash读写程序,目的是要将一个二进制文件写到SPI_FLASH中,最后通过开机读取,实际上这个.bin文件就是uboot和second-boot的结合体.通过SD卡写到SPI- ...
- Android基础知识点-Manifest清单文件
每个应用的根目录中都必须包含一个 AndroidManifest.xml 文件(且文件名精确无误). 清单文件向 Android 系统提供应用的必要信息,系统必须具有这些信息方可运行应用的任何代码. ...
- 无需密码通过scp命令+key的方式实现文件传输
如果觉得scp每次都要输入密码很麻烦, 那么这是解决方案.假设你平时在windows上开发,用户名是xiang, 你有一台Ubuntu服务器wdksw.com, 用户名是root.现在你准备上传一些文 ...
- 用类模拟C风格的赋值+返回值
这个方法比较好: class DataHolder: def __init__(self, value=None): self.value = value def set(self, value): ...
- RxJava操作符(05-结合操作)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51656736 本文出自:[openXu的博客] 目录: CombineLatest Join ...
- Dynamics CRM2013/2015 检索实体属性的两种方式
昨天有朋友问起如何查询一个字段属性是否存在于某个实体中,一般这个问题我们会采取最直观的查询方式即MetadataBrowser,该工具是一个zip解决方案包在SDK中的如下目录内"\SDK\ ...
- Android简易实战教程--第十一话《获取手机所有应用信息Engine类详解》
如果想要获取系统手机应用的详细信息,那么下边代码可以直接作为模板使用.笔者对每一行代码都做了注解,供您参考.直接上代码: package com.example.itydl.engines; impo ...
- C++对象模型的那些事儿之一:对象模型(上)
前言 很早以前就听人推荐了<深入理解C++对象模型>这本书,从年初买来到现在也只是偶尔翻了翻,总觉得晦涩难懂,放在实验室上吃灰吃了好久.近期由于找工作对C++的知识做了一个全面系统的学习, ...
- Android读取网络图片到本地的简约的实现
今天在网上看到了一个关于读取网络文件的小视频,觉得不错,拿来与大家分享 思路 具体的思路比较的简单,但是思想非常的单纯.那就是输入一个网址,点击按钮,将从网络上获取的一张图片显示到一个ImageVie ...