http://www.cnblogs.com/plokmju/p/android_Handler.html

android不允许在主线程里做耗时操作,如网络操作,以此来避免ANR

ANR(Application Not Responding)

http://baike.baidu.com/link?url=rLzKRNkjt79XITQKhRXp32alhsuKEt2FoHPw3vuB2UlEvyKOZwnEh4OYoPy4_fwO6zPPECXWre4ycip4mB0LOq

Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。

默认情况下,在android中Activity的最长执行时间是5秒,BroadcastReceiver的最长执行时间则是10秒。

因此如果想进行上述的操作,应该开启一个子线程。而在子线程中,android不允许进行UI操作。如果想在子线程中进行UI操作,就可以使用Handler开启UI线程。

Handler,它直接继承自Object,一个Handler允许发送和处理Message或者Runnable对象,并且会关联到主线程的MessageQueue中。每个Handler具有一个单独的线程,并且关联到一个消息队列的线程,就是说一个Handler有一个固有的消息队列。当实例化一个Handler的时候,它就承载在一个线程和消息队列的线程,这个Handler可以把Message或Runnable压入到消息队列,并且从消息队列中取出Message或Runnable,进而操作它们。

由上可知,Handler有两种用法:

  • Post:Post允许把一个Runnable对象入队到消息队列中。它的方法有:post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。
  • sendMessage:sendMessage允许把一个包含消息数据的Message对象压入到消息队列中。它的方法有:sendEmptyMessage(int)、sendMessage(Message)、sendMessageAtTime(Message,long)、sendMessageDelayed(Message,long)。

具体用法可以看第一个链接的文章

http://blog.csdn.net/gh102/article/details/7191486

这边对post的使用更加清晰一点

Post和message区别:

http://blog.csdn.net/u013168615/article/details/47024073

从源码中可以看出,post是调用了sendMessageDelayed方法:

public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), );
}

而其中的getPostMessage则是把Runnable r 包装成一个空Message然后返回,并将m的callback设为r

private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}

在handler源码里,则是调用了dispatchMessage(Message msg)的第一种方法,handleCallback()

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

而handleCallback()源码:

private final void handleCallback(Message message) {
message.callback.run();
}

就是直接调用了一开始传入的Runnable对象的run()方法

所以post方法也可以这样写:

public class MainActivity extends Activity {  

    private Handler handler;  

    @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
// 在这里进行UI操作
}
});
}
}).start();
}
}

我们在Runnable对象的run()方法里更新UI,效果完全等同于在handleMessage()方法中更新UI。

所以post和message没有本质区别,只是用法不同而已

handler.post和handler.sendMessage本质上是没有区别的,都是发送一个消息到消息队列中,而且消息队列和handler都是依赖于同一个线程的。

Handler源码解析:

http://blog.csdn.net/guolin_blog/article/details/9991569

由源码可知:

1.子线程里创建handler:

  new handler对象时一定要有一个Looper,而每个线程只有一个Looper,主线程的Looper在main函数里已经自动调用prepare方法创建了。如果我们想在子线程new handler,必须先调用Looper.prepare()方法

2.Handler到底是把Message发送到哪里去了呢?为什么之后又可以在Handler的handleMessage()方法中重新得到这条Message呢?

  • 首先handler每个发送消息的方法,实际上都是调用到了sendMessageAtTime(Message msg, long uptimeMillis)这个方法
  • sendMessageAtTime(Message msg, long uptimeMillis)方法通过enqueueMessage(Message msg, long when)将消息压入消息队列,并设置发送消息的时间
  • enqueueMessage(Message msg, long when)里定义里入队操作
  • MessageQueue并没有使用一个集合把所有的消息都保存起来,它只使用了一个mMessages对象表示当前待处理的消息。然后观察上面的代码的16~31行我们就可以看出,所谓的入队其实就是将所有的消息按时间来进行排序,这个时间当然就是我们刚才介绍的uptimeMillis参数。具体的操作方法就根据时间的顺序调用msg.next,从而为每一个消息指定它的下一个消息是什么。当然如果你是通过sendMessageAtFrontOfQueue()方法来发送消息的,它也会调用enqueueMessage()来让消息入队,只不过时间为0,这时会把mMessages赋值为新入队的这条消息,然后将这条消息的next指定为刚才的mMessages,这样也就完成了添加消息到队列头部的操作。
  • 出队操作在Looper.loop()方法里完成
  • 如果当前MessageQueue中存在mMessages(即待处理消息),就将这个消息出队,然后让下一条消息成为mMessages,否则就进入一个阻塞状态,一直等到有新的消息入队。继续看loop()方法的第14行,每当有一个消息出队,就将它传递到msg.target的dispatchMessage()方法中,那这里msg.target又是什么呢?其实就是Handler啦
  • dispatchMessage()调用handleMessage()方法


整个异步消息处理流程的示意图如下图所示:

UI线程和子线程在使用中可以这么封装:

public class ThreadUtils {

    /**
* 运行在子线程(发送数据)
*
* @param r
*/
public static void runInSubThread(Runnable r) {
new Thread(r).start();
} private static Handler handler = new Handler(); /**
* 运行在主线程(UI 线程 更新界面)
*
* @param r
*/
public static void runInUiThread(Runnable r) {
handler.post(r);// Message-->handler.sendMessage-->handleMessage()
// 主线程-->r.run();
}
}

Android-多线程Handler的更多相关文章

  1. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...

  2. Android多线程----异步消息处理机制之Handler详解

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  3. android 多线程Thread,Runnable,Handler,AsyncTask

    先看两个链接: 1.http://www.2cto.com/kf/201404/290494.html 2. 链接1: android 的多线程实际上就是java的多线程.android的UI线程又称 ...

  4. Android多线程源码学习笔记一:handler、looper、message、messageQueue

    最近在学习Android多线程相关知识的源码,现在把自己的笔记整理一下,写出来加深印象. Android多线程通讯的核心是handler.looper.message.messageQueue,这篇文 ...

  5. Android 多线程:使用Thread和Handler

    当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分 ...

  6. Android 多线程:使用Thread和Handler (从网络上获取图片)

    当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分 ...

  7. Android多线程编程<二>Handler异步消息处理机制之Message

      Message(消息):       一. Message的字段:    在Android中,Message作为线程之间(主要是子线程和UI主线程之间)数据交换的载体,通过Handler去传递.它 ...

  8. Android的Handler机制

    Handler机制的原理 Android 的 Handler 机制(也有人叫消息机制)目的是为了跨线程通信,也就是多线程通信.之所以需 要跨线程通信是因为在 Android 中主线程通常只负责 UI ...

  9. android 多线程

    本章讲述在android开发中,多线程的应用.多线程能够处理耗时的操作并优化程序的性能.本章主要介绍知识点,AsyncTask,Java线程池,ThreadPoolExecutor线程池类.本章案例只 ...

  10. android多线程断点续传下载文件

    一.目标 1.多线程抢占服务器资源下载. 2.断点续传. 二.实现思路. 假设分为三个线程: 1.各个线程分别向服务器请求文件的不同部分. 这个涉及Http协议,可以在Header中使用Range参数 ...

随机推荐

  1. 模拟实现strstr和strrstr

    strstr函数用于判断str2是否是str1的子串,如果是,则返回str2在str1中首次出现位置的地址,如果不是则返回NULL.其模拟实现代码如下:#include<iostream> ...

  2. [ActionScript 3.0] 透视投影

    下面的示例演示如何使用透视投影来创建 3D 空间.该示例演示如何通过projectionCenter属性来修改消失点和更改空间的透视投影.进行这种修改后,将强制重新计算focalLength和fiel ...

  3. svn提交新文件夹同时不需要更新全部上级目录

    关于svn的指定目录指定位置更新:当在提交了新建的目录后可以使用 a)  在需要更新的上级目录上单击右键 在延伸菜单中选择 b)  弹出对话框中选择,check repository c)  新添加的 ...

  4. python高级(三)—— 字典和集合(泛映射类型)

    本文主要内容 可散列类型 泛映射类型 字典 (1)字典推导式 (2)处理不存在的键 (3)字典的变种 集合 映射的再讨论 python高级——目录 文中代码均放在github上:https://git ...

  5. scrapyd 参考(https://www.jianshu.com/p/2a189127901a)

    一    Scrapyd简介 Scrapyd 是一个用来部署和运行 Scrapy 项目的应用,由 Scrapy 的开发者开发.其可以通过一个简单的 Json API 来部署(上传)或者控制你的项目. ...

  6. numpy的一维线性插值函数

    前言:      在用生成对抗网络生成二维数据点的时候遇到代码里的一个问题,就是numpy中的一维线性插值函数interp到底是怎么用的,在这个上面费了点功夫,因此现将其用法给出.      在生成对 ...

  7. crontab例行性共作

    一.单一工作调度 at [-mldv] TIME at -c 工作号码 -m:当at工作结束后,即是没有输出信息,以email通知用户该工作已完成 -l:at -l相当于atq,列出目前系统上所有的a ...

  8. php尝试调用一个图灵机器人

    1.需要到图灵机器人的网址,去注册一下账号.网址:http://www.tuling123.com/sso-web/index.html?ReturnURL=http%3A%2F%2Fwww.tuli ...

  9. git遇到的常见错误整理

    远程仓库与本地代码不一致 解决: git pull --rebase git@gitee.com:l544402029/MUTAO.git 将仓库里的代码pull下来  ,然后重新进行git add ...

  10. 项目中遇到的bug、问题总结

    1. Cannot set property 'captcha' of undefined 在node项目中使用svg-captcha生成验证码报错 captcha的代码,这里有一个session.c ...