Android中利用Handler实现消息的分发机制(三)
在第二篇文章《Android中利用Handler实现消息的分发机制(一)》中,我们讲到主线程的Looper是Android系统在启动App的时候,已经帮我们创建好了,而假设在子线程中须要去使用Handler的时候,我们就须要显式地去调用Looper的
prepare方法和loop方法,从而为子线程创建其唯一的Looper。
详细代码例如以下:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.v("Test", "Id of LooperThread : " + Thread.currentThread().getId());
...
}
}
};
Looper.loop();
}
}
而实际上,Android SDK 中已经提供了这样一个实现,一个叫做HandlerThread 的类,它继承了线程,而且在其run方法中调用了Looper.prepare() 和 Looper.loop() 方法,从而创建了一个已经有Looper的线程,如以下代码所看到的:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
我们在主线程中定义的Handler所相应的Looper,还是属于主线程的,那么事实上就仅仅是实现了在主线程中的异步处理而已。
而在日常开发中,当我们须要利用Handler在子线程中实现业务的处理的时候,我们就能够利用HandlerIntent来实现我们的需求。
普通情况下,我们会创建一个类,让其去继承HandlerThread, 例如以下:
public class MyHandlerThread extends HandlerThread {
public MyHandlerThread(String name) {
super(name);
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId());
MyHandlerThread myHandlerThread = new MyHandlerThread("MyHandlerThread");
myHandlerThread.start();
Handler handler = new Handler(myHandlerThread.getLooper(), new Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.v("Test", "id of Thread by Callback : " + Thread.currentThread().getId());
return false;
}
});
handler.sendEmptyMessage(0);
}
在样例中, 创建了一个MyHandlerThead 对象,记得,它是一个线程,所以须要调用其 start 方法,让线程跑起来。
接着,就须要利用Handler当中一个构造函数Handler(Looper, Callback) ,将HandlerThread线程中的 Looper 赋给handler,而随之传入的,则是Handler.Callback的接口实现类,如上面代码所看到的。
最后调用 sendMessage方法,相应的结果例如以下:
10-28 17:24:50.438: V/Test(31694): Id of MainThread : 1
10-28 17:24:50.448: V/Test(31694): id of Thread by Callback : 91617
可见,handleMessage的处理逻辑已经在是在另外一个线程中去跑了。
普通情况下,我们在创建handlerThread的时候,也会顺便实现Handler.Callback接口,将我们要实现的代码逻辑也封装在此线程中,让代码更具有可读性,例如以下:
public class MyHandlerThread extends HandlerThread implements Callback{
public MyHandlerThread(String name) {
super(name);
}
@Override
public boolean handleMessage(Message msg) {
Log.v("Test", "id of Thread by Callback : " + Thread.currentThread().getId());
return true;
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.v("Test", "Id of MainThread : " + Thread.currentThread().getId());
MyHandlerThread myHandlerThread = new MyHandlerThread("MyHandlerThread");
myHandlerThread.start();
Handler handler = new Handler(myHandlerThread.getLooper(), myHandlerThread);
handler.sendEmptyMessage(0);
}
说到代码的可读性,有时候,我们更加看重代码之间的层次或者说模块化,耦合度等特点。
不同的业务逻辑,不同的功能,应该实如今不同的模块中,而模块与模块之间就能够通过一个消息来通信,而这样的消息通讯方式,我们就能够利用Handler和HandlerThread来实现。
比方,近期做的一个浏览器的小Demo,其类图例如以下:
在当中,我们就利用了MessageDispatcher来存放各个模块的Handler,其结构例如以下:
private static MessageDispatcher mMsgDispatcher;
private SparseArray<Handler> mHandlers;
...
public void sendMessage(int target, int from, int msgWhat, Object obj){
Handler handler = mHandlers.get(target);
if(handler == null){
Logger.v("There is no Handler registered by target " + target);
return;
}
Message msg = handler.obtainMessage();
msg.what = msgWhat;
msg.obj = obj;
msg.arg1 = from;
handler.sendMessage(msg);
};
public void registerHanlder(int key, Handler handler){
mHandlers.put(key, handler);
}
public void unregisterHanlder(int key){
if(mHandlers.get(key) != null){
mHandlers.delete(key);
}
}
public void destroy(){
mHandlers = null;
}
在不同的模块实现中, 我们能够调用registerHandler方法,将其对象的Handler注冊到MessageDispatcher中,然后通过sendMessage方法,指定相应的目标,假设相应的目标模块也向MessageDispatcher,就能够获得其Handler,然后利用其Handler来发送消息,并由其处理。
比方,我们在BookmarkActivity中向BookmarkManager发送消息,例如以下:
mMessageDispatcher.sendMessage(MessageConstant.TARGET_BOOKMARK_MGR, MessageConstant.TARGET_BOOKMARK_ACTIVITY,
MessageConstant.MSG_BOOKMARK_GET_ALL_DIR, sparseArray);
而在BookmarkManager中,当其handler接受到相应的消息的时候,其就将会进行相应的处理,例如以下:
class BookmarkHandlerThread extends HandlerThread implements Callback{
public BookmarkHandlerThread(String name) {
super(name);
}
@SuppressWarnings("unchecked")
public boolean handleMessage(Message msg){
switch(msg.what){
case MessageConstant.MSG_BOOKMARK_GET_ALL_DIR:
//Do Something
这样,我们就行将业务逻辑和数据操作给分开了,实现了对功能编程。
尽管仅仅是一个不是非常成熟的想法,但还是希望可以跟大家分享一下,在设计代码架构的时候,可以依据功能,业务需求或者基础框架来进行分层,分块,实现代码的松耦合。
结束。
Android中利用Handler实现消息的分发机制(三)的更多相关文章
- 深入源代码解析Android中的Handler,Message,MessageQueue,Looper
本文主要是对Handler和消息循环的实现原理进行源代码分析.假设不熟悉Handler能够參见博文< Android中Handler的使用>,里面对Android为何以引入Handler机 ...
- Android正在使用Handler实现消息分发机制(零)
演讲前,AsyncTask文章.我们在最后谈到.AsyncTask它是利用Handler异步消息处理机制,操作结果.使用Message回到主线程,从而执行UI更新线程. 而在我们的日常开发工作,Han ...
- Android中的Handler机制
直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,如下错 误:android.view.ViewRoot$CalledFromWrongThreadException: ...
- Android中使用Handler造成内存泄露的分析和解决
什么是内存泄露?Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向 ...
- Android中使用Handler造成内存泄露
1.什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用 ...
- Android中的Handler的机制与用法详解
概述: 很多android初学者对android 中的handler不是很明白,其实Google参考了Windows的消息处理机制, 在Android系统中实现了一套类似的消息处理机制.在下面介绍ha ...
- android中的Handler和Runnable
最近在做一个项目,在网络请求时考虑用Handler进行处理,然后就研究了一下Handler和Runnable 首先在看一下java中的Runnable The Runnable interface s ...
- 转:Android中的Handler的机制与用法详解
注:Message类的用法: message的几个参数都可以携带数据,其中arg1与arg2可以携带int类型,what是用户自定义的int型,这样接受者可以了解这个消息的信息. 说明:使用Messa ...
- Android中的Handler,以及用Handler延迟执行
项目中遇到一个情况,先生成文件再上传:但有时候发出指令后上传会不成功,需要再发一次指令方能上传. 猜想是由于文件还没生成就执行「上传」指令了.想到要延时.Android中单纯用currentThrea ...
随机推荐
- 为什么在Python3.4.1里输入print 10000L或10000L失败
打开Python的命令行交互窗体,而且在里面进行以下的输入: Python 3.4.1 (v3.4.1:c0e311e010fc, May 18 2014, 10:38:22) [MSC v.1600 ...
- 跑Java -jar somefile.jar时会发生什么(一个)
最近阅读JVM源代码.一些想法写Blog分享.于是,他开了这么一个新课题. 第一篇文章取名字的时候让我很困惑,我代码的阅读是从Launcher開始入手的,也就是Java.exe(假设是windows平 ...
- Android应用UI架构
这个标题听起来可能有点大.事实上这里主要就是讨论一个应用程序的UI组件,是全用Activity还是全用Fragment.或者是二者皆有.以及使用Activity和Fragment的一些注意事项. A ...
- Deep Learning Papers
一.Image Classification(Recognition) lenet: http://yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf alexn ...
- php_linux_centos6.4_安装mysql_apache_php
原文:php_linux_centos6.4_安装mysql_apache_php 原文 : http://blog.csdn.net/xiaoliouc/article/details/176395 ...
- MongoDB初学者的配置环境和基础设施的使用
一个.mongoDB安装 1.第一MongoDB官方网站下载安装包http://www.mongodb.org/. 依照自己的操作系统进行下载. 2.在硬盘上建立两个文件夹分辨存放mongoDB安装文 ...
- 如何让格斗游戏的横版过关(2) Cocos2d-x 2.0.4
在第一章<如何使横版格戏>基础上.添加角色运动.碰撞.敌人.AI和音乐音效,原文<How To Make A Side-Scrolling Beat 'Em Up Game Like ...
- 图片 Base64码 转换
import sun.misc.BASE64Decoder; private String getBase64Picture(String imgBase64Str) { FileOutputStre ...
- NSOJ 畅通工程(并查集)
某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路可达即可). ...
- Eclipse:引用一个项目作为库(图文教程)
前言:工程TestRoid要引用Volley项目作为一个库 过程,如下面: 一:选择导入Android工程 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc ...