Android中Handler原理
Handler主要是主线程和子线程通信。一般子线程中做一些耗时操作做完之后通知主线程来改动UI。
实际上android系统在Activity启动或者状态变化等都是通过Handler机制实现的。
首先进入到ActivityThread的main方法中
public static void main(String[] args) {
……
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false); if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
……
Looper.loop();
……
}
以下主要分析上面几句代码。
1. Looper.prepareMainLooper();
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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对象
}
Looper的构造函数例如以下
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);//Looper维护了一个消息队列
mRun = true;
mThread = Thread.currentThread();
}
小结:在调用完Loop.prepare后。就会为当前线程创建一个消息泵Looper,这个Looper维护了一个消息队列MessageQueue
2. sMainThreadHandler =thread.getHandler();
sMainThreadHandler是Handler对象。getHandler方法例如以下:
final Handler getHandler() {
return mH;
}
看到mH在前面定义为final H mH = new H();实际上H是继承自Handler。部分代码例如以下:
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
……
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
……
}
……
}
小结:这里相当于平时在UI线程中创建一个Handler实现他的handlerMessage方法。
3.Looper.loop();
public static void loop() {
……
final MessageQueue queue = me.mQueue;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
……
msg.target.dispatchMessage(msg);
……
msg.recycle();
}
}
小结:调用Looper.loop()。能够看到for循环。不停地从消息队列中取消息。然后分发msg.target.dispatchMessage(msg); 这里的msg.target就是Handler对象,指的是处理该Message的Handler。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
调用dispatchMessage。假设Message设置了回调函数就运行回调,否则假设定义Handler的时候假设传进了回调函数就运行传进的回调,不然就会运行handlerMessage函数,能够看到是有优先级顺序的。系统处理的时候因为未设置回调,就会运行handlerMessage。
比方上面的当收到LAUNCH_ACTIVITY消息,就会运行handleLaunchActivity---- performLaunchActivity---- mInstrumentation.newActivity(cl,component.getClassName(), r.intent); -----mInstrumentation.callActivityOnCreate(activity,r.state); ----- activity.performCreate(icicle);
这样就运行到了我们平时所谓的Activity的入口onCreate方法。
到如今我们看到了Handler机制在android中的应用。
接下来分析一下handler和Looper是怎么关联起来的。
Handler的构造函数终于都会去运行
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();//获取当前线程的Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//将Looper对象的消息队列传给Handler的成员,使得Handler就能够操作该消息循环
mCallback = callback;
mAsynchronous = async;
}
Message类例如以下
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
……
Handler target; //每一个消息都有一个成员保存和他关联的Handler
Runnable callback;
}
接下来我们看一下调用handler的sendMessage送消息时发生了什么
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
最后会运行到:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//在这里将this复制给Message的Handler成员。this也就是我们定义的handler对象。
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);//然后加入到消息队列里面
}
msg.target = this;所以就有了在loop消息循环函数中的msg.target.dispatchMessage(msg);来分发消息。因为多台就会运行我们实现的handlerMessage里面的代码。
Android中Handler原理的更多相关文章
- Android中Handler 、Thread和Runnable之间的关系
在多线程编程的时候,我们经常会用到Handler,Thread和Runnable这三个类,我们来看看这三个类之间是怎么样的关系? 首先说明Android的CPU分配的最小单元是线程,Handler一般 ...
- Android中Handler作用
在Android的UI开发中,我们经常会使用Handler来控制主UI程序的界面变化.有关Handler的作用,我们总结为:与其他线程协同工作,接收其他线程的消息并通过接收到的消息更新主UI线程的内容 ...
- Android中Handler使用浅析
1. Handler使用引出 现在作为客户,有这样一个需求,当打开Activity界面时,开始倒计时,倒计时结束后跳转新的界面(思维活跃的朋友可能立马想到如果打开后自动倒计时,就类似于各个APP的欢迎 ...
- Android中Handler的消息处理机制以及源码分析
在实际项目当中,一个很常见的需求场景就是在根据子线程当中的数据去更新ui.我们知道,android中ui是单线程模型的,就是只能在UI线程(也称为主线程)中更新ui.而一些耗时操作,比如数据库,网络请 ...
- Android 中 Handler 引起的内存泄露
在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.其实这可能导致内存泄露,代码中哪里可能导致内存泄露,又是如何导致内存泄露的呢?那我们就慢慢分析一下.http://w ...
- android中handler用法总结
一.Handler的定义: Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中 ...
- Android中Handler引起的内存泄露
在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 1 2 3 4 5 6 7 8 9 public class SampleActivit ...
- Android中Handler的使用
当我们在处理下载或是其他需要长时间执行的任务时,如果直接把处理函数放Activity的OnCreate或是OnStart中,会导致执行过程中整个Activity无响应,如果时间过长,程序还会挂掉.Ha ...
- Android中Handler的使用方法及实例(基础回顾)
Handler使用例1 这个例子是最简单的介绍handler使用的,是将handler绑定到它所建立的线程中.本次实验完成的功能是:单击Start按钮,程序会开始启动线程,并且线程程序完成后延时1s会 ...
随机推荐
- ASPX和Razor
ASPX ASPX文件是微软的在server端运行的动态网页文件,通过IIS解析运行后能够得到动态页面,是微软推出的一种新的网络编程方法,而不是ASP的简单升级,由于它的编程方法和ASP有非常大的不同 ...
- Unity5.1 新的网络引擎UNET(七) UNET 单人游戏转换为多人
单人游戏转换为多人 孙广东 2015.7.12 本文档描写叙述将单人游戏转换为使用新的网络系统的多人游戏的步骤.这里描写叙述的过程是简化,对于一个真正的游戏事实上须要更高级别版本号的实际 ...
- php global GLOBALS[]变量
$a=123; function aa() { Global $a; //如果不把$a定义为global变量,函数体内是不能访问函数体外部的$a的,但是可以定义一个相同的名字$a,此时这个变量是局部变 ...
- 15. 3Sum[M]三数之和
题目 Given an array nums of n integers, are three elements a, b, c in nums such that a+b+c=0? Find all ...
- NOIp2018之前打模板出现的问题汇总
灵感来源是因为调试了一下午dij,就想把错误记下来 dij:结构体里的重载运算符不会写 结构体声明后要加引号 用于排序的结构体按照边长度排序 匈牙利:在dfs中的if语句中,要继续搜 ...
- 判断是否是Ajax请求
Request.IsAjaxRequest()判断是否是ajax请求原理:Http协议上有个X-Requested-With:XML HttpRequest属性判断的 mvc后台通过Request可以 ...
- 微信小程序 | canvas绘图
1.新的尺寸单位 rpx rpx(responsive pixel): 可以根据屏幕宽度进行自适应. 规定屏幕宽为750rpx.如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则 ...
- BroadcastReceiver register 广播的动态注册方式
1.动态注册方式特点:在代码中进行注册后,当应用程序关闭后,就不再进行监听. 下面是具体的例子: BroadcastTest.java package com.czz.test; import and ...
- Python 之 入门须知
1.Python2.0不支持中文,3.0支持 2.版本问题
- (转)GPT磁盘与MBR磁盘区别
摘要: Windows 2008磁盘管理器中,在磁盘标签处右击鼠标,随磁盘属性的不同会出现“转换到动态磁盘”,“转换到基本磁盘”“转换成GPT磁盘”,“转换成MBR磁盘”等选项,在此做简单介绍.部 ...