Android学习--后台线程之Looper、Handler、HandlerThread
来源:互联网 发布:魔兽世界nga数据库 编辑:程序博客网 时间:2024/05/08 05:32
利用AsyncTask获得后台线程适用于那些短暂且较少重复的任务,而当有重复且长时间运行的任务需要后台运作时,我们可以用到Looper,Handler,与HandlerThread。
Android系统中,线程使用的收件箱叫做消息队列(Message Queue)。使用消息队列的线程叫做消息循环(Message Loop)。消息循环会不断循环检查队列上是否有新消息。消息循环由一个线程和一个Looper组成。Looper对象管理着线程的消息队列。在使用Looper时,我们会使用一个HandlerThread类。(主线程也是一个消息循环,因此具有一个Looper。主线程的所有工作都是由其Looper完成的,Looper不断从消息队列中抓取消息,然后完成消息指定的任务。)
消息是Message类的一个实例,包含有好几个实例变量。其中有三个需在实现时定义:
What:用户定义的int型消息代码,用来描述消息;
Obj:随消息发送的用户指定对象;
Target:处理消息的Handler。
要处理消息以及消息指定的任务,首先需要一个消息Handler实例。Handler不仅仅是处理Message的目标(Target),也是创建和发布Message的接口。
Looper拥有Message对象的收件箱,所以Message必须在Looper上发布或读取。而一个Handler仅与一个Looper相关联,一个Message也仅与一个目标Handler相关联。而多个Handler可与一个Looper相关联。这意味着一个Handler的Message可能与另一个Handler的Message存放在同一消息队列中。
消息的目标Handler通常不需要手动设置。理想方式是调用Handler.obtainMessage()方法创建信息并传入其他消息字段,然后该方法会自动完成目标Handler的设置。而此方法也会从公共循环池里获取消息,避免创建新的Message对象。
一旦获得Message,我们就调用sendToTarget()方法将其发送给它的Handler。紧接着Handler会将Message防止在Looper消息队列的尾部。如下代码显示:
Public class ThumbnailDownloader<Token> extends HandlerThread { ... Private static final int MESSAGE_DOWNLOAD = 0; Handler mHandler; Map<Token , String> requestMap = Collections.synchronizedMap(new HashMap<Token , String>()); @SuppressLint(“HandlerLeak”) @Override Protected void onLooperPrepared(){ //该方法在Looper第一次检查消息队列前就调用 mHandler = new Handler() { //在Handler子类中创建Handler实现 @Override Public void handleMessage(Message msg){ If(msg.what == MESSAGE_DOWNLOAD){ @SuppressWarnings(“unchecked”) Token token = (Token)msg.obj; handleRequest(token); } } }; } Public void queueThumbnail(Token token , String url){ requestMap.put(token , url); mHandler.obtaninMessage(MESSAGE_DOWNLOAD , token) //该方法会自动完成 //Handler的设置 .sendToTarget(); //将获得的Message发送给它的Handler } Private void handleRequest(final Token token){ .... }}
Public class PhotoGalleryFragment extends Fragment { ThumbnailDownloader<ImageView> mThumbnailThread; @Override Public void onCreate(Bundle savedInstanceState){ ... mThumbnailThread = new ThumbnailDownloader<ImageView>(); mThumbnailThread.start(); mThunbnailThread.getLooper(); //getLooper()方法要在start方法之后, //为了保证线程就绪 } @Override Public void onDestroy(){ super.onDestroy(); mThumbnailThread.quit(); //结束线程的quit()方法要在onDestroy()中完成 }}
下面介绍的是HandlerThread如何访问主线程。
主线程是一个拥有Handler和Looper的消息循环。主线程上创建的Handler会自动与它的Looper相关联。我们可以将主线程上创建的Handler传递给另一线程。传递出去的Handler与创建它的线程Looper始终保持着联系。因此,任何已传出Handler负责处理的消息都将在主线程的消息队列中处理。所以我们利用Handler的传递既可以实现在主线程上安排后台线程上的任务,也可以在后台线程上安排要在主线程上完成的任务。
方法是在HandlerThread上添加mResponseHandler变量,以存放来自于主线程的Handler。然后构造一个接受Handler的构造方法,最后增加一个用来通信的监听器借口。实现代码如下:
Public class ThumbnailDownloader <Token> extends HandlerThread{ //添加反馈Handler ... Handler mResponseHandler; Listener<Token> mListener; Public interface Listener<Token> { Void onThumbnailDownloaded( Token token , Bitmap thumbnail ); } Public void setListener( Listener<Token> listener ){ mListener = listener; } Public ThumbnailDownloader( Handler responseHandler ){ mResponseHandler = responseHandler; }}
Public class PhotoGalleryFragment extends Fragment { //关联使用反馈Handler ... @Override Public void onCreate(Bundle savedInstanceState){ ... mThumbnailThread = new ThumbnailDownloader<ImageView>(); mThumbnailThread = new ThumbnailDownloader<imageView>( new Handler() ); mThumbnailThread.setListener(new ThumbnailDownloader.Listener<ImageView>() { Public void onThumbnailDownloaded(ImageView imageView , Bitmap thumbnail){ If(isVisible()){ imageView.setImageBitmap(thumbnail); } } }); mThumbnailThread.start(); mThunbnailThread.getLooper(); //getLooper()方法要在start方法之后, //为了保证线程就绪 } ...}
如上,通过mResponseHandler,ThumbnailDownloader能够访问与主线程Looper绑定的Handler。另外,我们也可以返回定制Message给主线程,这里有一种方便的方法,就是利用Handler的post(Runnable)方法,实现如下:
Public class ThumbnailDownloader<Token> extends HandlerThread { Private void handleRequest(final Token token){ .... mResponseHandler.post(new Runnable() { Public void run(){ If(requestMap.get(token) != url) Return; requestMap.remove(token); mListener.onThumbnailDownloaded(token , bitmap); } }); }}
最后,记得添加清理方法清除队列外的所有请求。
Public void clearQueue(){ mHandler.removeMessages(MESSAGE_DOWNLOAD); requestMap.clear();}
@OverridePublic void onDestroyView(){ super.onDestroyView(); mThumbnailThread.clearQueue();}
- Android学习--后台线程之Looper、Handler、HandlerThread
- Android Looper,handler,HandlerThread
- Android HandlerThread Handler Looper 三类之间的联系--学习
- Android异步消息之Looper、Handler、Message、HandlerThread的关系
- Android Handler 绑定自定义线程之HandlerThread
- Android中的Looper、Handler与HandlerThread
- [Android]Handler-Looper-MessageQueue-Message、HandlerThread
- Android 的Handler、Looper与HandlerThread
- Android HandlerThread、Looper、Handler 知识点梳理
- Android: Looper, Handler, HandlerThread. Part I
- Android: Looper, Handler, HandlerThread. Part II
- Android:Looper, Handler, And HandlerThread(二)
- Understanding Android Core: Looper, Handler, and HandlerThread
- Android的Looper和Handler和HandlerThread
- Handler Looper HandlerThread
- HandlerThread, Handler, Looper
- Looper,Handler,HandlerThread
- Looper、Handler与HandlerThread
- ::在C++中是什么意思
- 快速掌握一个语言最常用的50%
- CardView使用介绍
- linux配置java环境变量
- 另一种二叉树非递归遍历的实现
- Android学习--后台线程之Looper、Handler、HandlerThread
- 树型dp
- 重新写博声明
- 监督学习简介
- webservice WSDL java例子
- mysql常用函数汇总
- iOS中状态栏的小结
- Android---NDK编译静态库失败
- ubuntu中修改计算机名