参考资料:

http://www.cnblogs.com/qlky/p/5657924.html

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

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

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

http://www.jianshu.com/p/02962454adf7

http://www.jianshu.com/p/ac50ba6ba3a2

可以看到有这么多的资料,内容也很多,看的眼花缭乱。我决定自己总结一下,从最简单的开始,再慢慢补细节。

Handler

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

  • 作用

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有两种用法:

  • 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://www.cnblogs.com/plokmju/p/android_Handler.html

两个实例

第一个是post的,处理在子线程修改UI

public class HandlerPostActivity1 extends Activity {
private Button btnMes1,btnMes2;
private TextView tvMessage;
// 声明一个Handler对象
private static Handler handler=new Handler(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.message_activity); btnMes1=(Button)findViewById(R.id.btnMes1);
btnMes2=(Button)findViewById(R.id.btnMes2);
tvMessage=(TextView)findViewById(R.id.tvMessage);
btnMes1.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
// 新启动一个子线程
new Thread(new Runnable() {
@Override
public void run() {
// tvMessage.setText("...");
// 以上操作会报错,无法再子线程中访问UI组件,UI组件的属性必须在UI线程中访问
// 使用post方式修改UI组件tvMessage的Text属性
handler.post(new Runnable() {
@Override
public void run() {
tvMessage.setText("使用Handler.post在工作线程中发送一段执行到消息队列中,在主线程中执行。");
}
});
}
}).start();
}
});
}
}

第二个是Message的,子线程改变UI

public class HandlerMessageActivity2 extends Activity {
private Button btn1, btn2, btn3, btn4,btn5;
private static TextView tvMes;
private static Handler handler = new Handler() {
@Override
public void handleMessage(android.os.Message msg) {
if (msg.what == 3||msg.what==5) {
tvMes.setText("what=" + msg.what + ",这是一个空消息");
} else {
tvMes.setText("what=" + msg.what + "," + msg.obj.toString());
} };
}; @Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.message_activity2);
tvMes = (TextView) findViewById(R.id.tvMes);
btn1 = (Button) findViewById(R.id.btnMessage1);
btn2 = (Button) findViewById(R.id.btnMessage2);
btn3 = (Button) findViewById(R.id.btnMessage3);
btn4 = (Button) findViewById(R.id.btnMessage4);
btn5 = (Button) findViewById(R.id.btnMessage5); btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 使用Message.Obtain+Hander.sendMessage()发送消息
new Thread(new Runnable() {
@Override
public void run() {
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "使用Message.Obtain+Hander.sendMessage()发送消息";
handler.sendMessage(msg);
}
}).start();
}
}); btn2.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
// 使用Message.sendToTarget发送消息
new Thread(new Runnable() {
@Override
public void run() {
Message msg = Message.obtain(handler);
msg.what = 2;
msg.obj = "使用Message.sendToTarget发送消息";
msg.sendToTarget();
}
}).start();
}
}); btn3.setOnClickListener(new View.OnClickListener() {
// 发送一个延迟消息
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
handler.sendEmptyMessage(3);
}
}).start();
}
}); btn4.setOnClickListener(new View.OnClickListener() { @Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
Message msg = Message.obtain();
msg.what =4;
msg.obj = "使用Message.Obtain+Hander.sendMessage()发送延迟消息";
handler.sendMessageDelayed(msg, 3000);
}
}).start();
}
}); btn5.setOnClickListener(new View.OnClickListener() {
// 发送一个延迟的空消息
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
handler.sendEmptyMessageDelayed(5, 3000);
}
}).start();
}
});
}
}
  • 原理

从作用可以知道,需要解决在子线程修改UI的问题。而UI只能在主线程修改,所以问题就变成了怎么让子线程随时能告诉主线程该怎么做。

android给出的方案是这样的:

1.因为代码执行完会结束,而主线程需要随时响应不能结束,所以主线程需要在一个死循环里面等待消息:Looper

2.主线程需要在开启死循环前,设立一个接受和处理消息的机制(包括跳出循环的消息):Handler

3.需要规定消息的种类和载体:Message

4.同一线程在同一时间只能处理一个消息,所以需要保存消息的顺序和时间,一条条拿出来处理:MessageQueue

5.由于同一进程中线程和线程之间资源是共享的,所以任何线程都可以获取到MessageQueue实例,然后向主线程发送消息

所以Handler实际上就是主线程接收和处理消息的一个封装。在子线程new Handler()时帮你获得MessageQueue实例,并封装发送消息的方法。在主线程MessageQueue处理消息时又封装了Handler来处理消息。

一个最标准的异步处理线程(也是将普通线程转成Looper线程的方法):

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();
}
}

三种在子线程改变UI的方法

1. Handler的post()方法

2. View的post()方法

3. Activity的runOnUiThread()方法

Handler.post

我们先来看下Handler中的post()方法,代码如下所示:

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

其实就是sendMessageDelayed(),再看getPostMessage()

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

dispatchMessage()方法中有做一个检查,如果Message的callback等于null才会去调用handleMessage()方法,否则就调用handleCallback()方法

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

所以所谓callback就是子线程我们创建的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();
}
}

View中的post()方法

public boolean post(Runnable action) {
Handler handler;
if (mAttachInfo != null) {
handler = mAttachInfo.mHandler;
} else {
ViewRoot.getRunQueue().post(action);
return true;
}
return handler.post(action);
}

用的就是handler的post,不解释了

Activity中的runOnUiThread()方法

public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}

如果当前的线程不等于UI线程(主线程),就去调用Handler的post()方法,否则就直接调用Runnable对象的run()方法。还有什么会比这更清晰明了的吗?

为什么要用Message.obtain()而不是new Message();

Message Pool消息池
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}

我们通过obtain方法取出一条消息的时候,如果发现当前的消息池不为空,那就直接重复利用Message(已经被创建过和handle过的);如果为空就重新new 一个消息。这就是一种享元设计模式的概念。例如在游戏里面,发子弹,如果一个子弹是一个对象,一按下按键就发很多个子弹,那么这时候就需要利用享元模式去循环利用了。

Handler与Android四大组件生命周期

http://www.jianshu.com/p/ac50ba6ba3a2

除了客户端的handler外,还有系统handler,用来处理系统的操作消息:比如启动Activity等四大组件

一小段代码,应用程序的入口:

public final class ActivityThread {
public static final void main(String[] args) {
......
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false); if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
Looper.loop();
......
}
}
  • ActivityThread并不是一个线程,它并没有继承Thread,而只是一个普通的类public final class ActivityThread{...}ActivityThread的构造函数并没有做什么事只是初始化了资源管理器。
  • thread.attach(false);便会创建一个Binder线程(具体是指ApplicationThread,该Binder线程会通过想 HandlerMessage发送给主线程,之后讲)
  • 在Looper.loop()中进入死循环

插入一个问题:

主线程是UI线程和用户交互的线程,优先级应该很高,主线程的死循环一直运行是不是会特别消耗CPU资源吗?App进程的其他线程怎么办?

  • 这基本是一个类似生产者消费者的模型,简单说如果在主线程的MessageQueue没有消息时,就会阻塞在loop的queue.next()方法里,这时候主线程会释放CPU资源进入休眠状态,直到有下个消息进来时候就会唤醒主线程,在2.2 版本以前,这套机制是用我们熟悉的线程的wait和notify 来实现的,之后的版本涉及到Linux pipe/epoll机制,通过往pipe管道写端写入数据来唤醒主线程工作。原理类似于I/O,读写是堵塞的,不占用CPU资源。

系统Handler

final H mH = new H();

在new ActivityThread的时候,系统的Handler就就初始化了,这是一种饿加载的方法,也就是在类被new的时候就初始化成员变量了。另外还有一种懒加载,就是在需要的时候才去初始化,这两种方式在单例设计模式里面比较常见。

系统是怎么发消息给主线程的,主线程是怎么处理这些个消息的?

在准备启动一个Activity的时候,系统服务进程下的ActivityManagerService(简称AMS)线程会通过Binder发送IPC调用给APP进程,App进程接到到调用后,通过App进程下的Binder线程最终调用ActivityThread类下面的scheduleLaunchActivity方法来准备启动Activity

注:Binder线程:具体是指ApplicationThread,在App进程中接受系统进程传递过来的信息的线程(在主线程进入死循环之前创建了这个线程)。

看下scheduleLaunchActivity方法:

//这个方法不是在主线程调用,是Binder线程下调用的
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { updateProcessState(procState, false); ActivityClientRecord r = new ActivityClientRecord(); .... sendMessage(H.LAUNCH_ACTIVITY, r);
}

把启动一些信息封装成ActivityClientRecord之后,最后一句调用sendMessage(H.LAUNCH_ACTIVITY, r);

再看这个方法:

private void sendMessage(int what, Object obj) {
sendMessage(what, obj, 0, 0, false);
}
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}

很清楚了,APP下的Binder就是用系统handler来启动activity的

总结

Android-消息处理学习总结(Handler,Looper)的更多相关文章

  1. 【Android 开发】: Android 消息处理机制之一: Handler 与 Message

    最近几讲内容,我们学习了Android中关于多线程的一些知识,上一讲我们讲解了异步任务 AsyncTask 的操作,Android中还提供了其他的线程操作,如Handler Message Messa ...

  2. 解析Android消息处理机制:Handler/Thread/Looper & MessageQueue

    解析Android消息处理机制 ——Handler/Thread/Looper & MessageQueue Keywords: Android Message HandlerThread L ...

  3. Android之消息机制Handler,Looper,Message解析

    PS:由于感冒原因,本篇写的有点没有主干,大家凑合看吧.. 学习内容: 1.MessageQueue,Looper,MessageQueue的作用. 2.子线程向主线程中发送消息 3.主线程向子线程中 ...

  4. Android消息机制探索(Handler,Looper,Message,MessageQueue)

    概览 Android消息机制是Android操作系统中比较重要的一块.具体使用方法在这里不再阐述,可以参考Android的官方开发文档. 消息机制的主要用途有两方面: 1.线程之间的通信.比如在子线程 ...

  5. android学习11——Handler,Looper,MessageQueue工作原理

    Message是Handler接收和处理的消息对象. 每个线程只能拥有一个Looper.它的loop方法读取MessageQueue中的消息,读到消息之后就把消息交给发送该消息的Handler进行处理 ...

  6. (转)Android消息处理机制(Handler、Looper、MessageQueue与Message)

    转自 http://www.cnblogs.com/angeldevil/p/3340644.html Android消息处理机制(Handler.Looper.MessageQueue与Messag ...

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

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

  8. Android中消息系统模型和Handler Looper

    http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html Android中消息系统模型和Handler Looper 作为Andro ...

  9. Android源码解析——Handler、Looper与MessageQueue

    本文的目的是来分析下 Android 系统中以 Handler.Looper.MessageQueue 组成的异步消息处理机制,通过源码来了解整个消息处理流程的走向以及相关三者之间的关系 需要先了解以 ...

  10. Android的消息循环机制 Looper Handler类分析

    Android的消息循环机制 Looper Handler类分析 Looper类说明   Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在ru ...

随机推荐

  1. 【转】C#如何创建泛型类T的实例

    原文地址:https://www.cnblogs.com/lxhbky/p/6020612.html 最近在学历基类的写法时,遇到了一个问题:如何怎么创建一个泛型类T的实例呢?     废话不多说了, ...

  2. 【转】Windows IIS注册asp 此操作系统版本不支持此选项 错误解决方法

    原文:https://blog.csdn.net/sweety820/article/details/79538973 更新Win10,原来的IIS站点访问不了,原因是因为IIS 没有.net 4.5 ...

  3. 设计模式:Builder

    简介 建造者模式(Builder),将一个复杂对象的表示和它的构建分离,这样同样的构造过程可以创建出不同的对象状态. 类图 下面的Product是要创建的对象的目标类型,产品. Builder 创建一 ...

  4. tcp server

    SO_REUSEADDR Ignore SIGPIPE TCP_NODELAY TCP_QUICKACK

  5. 设计模式《JAVA与模式》之迭代子模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述迭代子(Iterator)模式的: 迭代子模式又叫游标(Cursor)模式,是对象的行为模式.迭代子模式可以顺序地访问一个聚集中的元素而不 ...

  6. app绘制手势密码 、九宫格分解

    什么是九宫格? 即是我们常见的手势绘制.一共有9个点,让我们进行绘制手势.我们手动操作的时候,通过是按住第一个点,然后移动到最后一点,然后松开,就完成手势的操作,那么,如果要用自动化代码,来让其自动绘 ...

  7. 【sping揭秘】11、Java 平台上的AOP实现机制

    动态代理 Jdk1.3只有引入的动态代理机制,可以再运行期间,为相应的接口(必须得有接口)动态生成对应的代理对象 基于以上问题,我们可以将横切关注点逻辑封装到动态代理的invocationhandle ...

  8. How To Crop Bitmap For UWP

    裁剪图片主要是借助于 BitmapDecoder.GetPixelDataAsync() 以及 BitmapTransform对象来实现. 实现的代码如下: using System; using S ...

  9. 【从0到1学jQuery】jQuery中each()和$.each()的使用

    引子: 最近遇到一个问题,就是在each()函数中怎么模拟for循环中的break和continue的操作.所以就查看了jQuery关于这个函数的文档,并且总结一下. 演示代码如下: <div& ...

  10. PHP多进程系列笔记(四)

    本节主要讲解Posix常用函数和进程池的概念,也会涉及到守护进程的知识.本节难度较低. Posix常用函数 posix_kill 向指定pid进程发送信号.成功时返回 TRUE , 或者在失败时返回 ...