异步消息处理机制(一)

来源:互联网 发布:苹果cms采集规则教程 编辑:程序博客网 时间:2024/06/16 17:44

Handler

一、什么是Handler

handler通过发送和处理Message和Runnable对象关联相对应线程的MessageQueue

1、可以让对应的Message和Runnable在未来的某个时间点进行相应的处理
2、让自己想要处理的耗时操作放在子线程,让更新UI的操作放在主线程。

二、hander的内部原理

在Handler的构造函数创建了一个Looper(通过ThreadLocal保存当前线程的Looper),又通过Looper创建了一个MessageQueue。

发送消息: 1、post(Runnable) 2、sendMessage(Message)

读取消息: Looper通过prepare()方法将Looper对象保存在ThreadLocal中 ,loop()方法循环从MessageQueue读取消息。

处理消息: 内部有一个dispatchMessage,有callback(Runnable)会执行线程的run方法,否则执行handleMessage方法(需要在Activity中实现这个方法)。

三、hander 引起的内存泄露以及解决办法

原因:匿名内部类持有外部类的匿名引用,导致外部activity无法释放

解决办法:1、handler内部持有外部activity的弱引用 2、把handler改为静态内部类 3、在activity销毁时调用hanler.removeCallback

两个面试中的小问题:

1、为什么Android中要设计为只能在UI线程中去更新UI呢?

(1)解决多线程并发问题(根本原因)你可能会说,既然是担心多线程并发问题,那我在子线程中加锁进行更新UI行不行呢?你这样想的话,会容易造成UI卡顿的,而且性能也不好。
(2)提高界面更新的性能问题
(3)架构设计的简单, Android中之所以说架构简单,是因为帮我们封装了很多更新UI的操作。

2、handler可以在子线程创建吗?
可以,但是需要先Looper.prepare()创建一个Looper对象并保存在ThreadLocal中,否则会报can’t create handler inside thread that has not called Looper.prepare()。

AsyncTask

1、本身是一个静态的线程池,它派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。
2、线程池中的工作线程执行doInBackground方法执行异步任务
3、当任务状态改变之后,工作线程会向UI线程发送消息,内部使用handler响应这些消息,并调用相关的回调函数

注意事项

1、内存泄露 , 匿名内部类持有外部类的匿名引用
2、生命周期,在activity销毁时要调用cancel方法去取消这个正在执行的task,调用cancel()方法
3、结果丢失,如果当前的activity重新创建会导致之前的那个引用无效
4、串行或者并行

Android API中有提到,AsyncTask非常适合短时间异步操作。如果要执行长时间操作,最好使用线程池Executor
AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask.
也许很多人会有疑问,这是为什么呢?后来我在stackoverflow上找到了一个比较好的回答。
提到了两个原因:
1、AsyncTask的生命周期没有跟Activity的生命周期同步
2、容易内存泄露

微信公众号

这里写图片描述

原创粉丝点击