在第二篇文章《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 ...
随机推荐
-
HTML Meta中添加X-UA-Compatible和IE=Edge,chrome=1有什么作用
你好,这个属性主要是设置浏览器优先使用什么模式来渲染页面的.常见写法如下:<meta http-equiv="X-UA-Compatible" content="I ...
-
[LeetCode] Add Digits (a New question added)
Given a non-negative integer num, repeatedly add all its digits until the result has only one digit. ...
-
学习笔记4_ServletContext(重要整个Web应用的动态资源之间共享数据)
ServletContext(重要) 一个项目只有一个ServletContext对象! 我们可以在N多个Servlet中来获取这个唯一的对象,使用它可以给多个Servlet传递数据! 与天地同寿!! ...
-
idea 找不到classpath 为resource下的xml
注入时不能自动找到在src/main/resources下的xml. @ContextConfiguration(locations = { "classpath:applicationCo ...
-
PreferencesUtils【SharedPreferences操作工具类】
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 可以替代ACache用来保存用户名.密码. 相较于Acache,不存在使用猎豹清理大师进行垃圾清理的时候把缓存的数据清理掉的问题. ...
-
jmeter5.1测试websocket接口
jmeter没有websocket协议的取样器,需要我们自己开发,但是网上已经有大神先开发好了,[相关jar包,点击左侧加群获取] 只需要放到jmeter的ext目录(D:\apache-jmeter ...
-
CentOS7之Rsync+Inotify架构实现实时同步文件和文件夹
简介:rsync是用来同步文件和文件夹的,inotify是用来实现监听变动而自动同步的 OS:Centos7.3 服务器端:172.16.13.157 客 户 端 :172.16.13.156 目 ...
-
C 语言经典例子
1. 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. #inc ...
-
将 HttpPostedFile 转换成 Image 或者 Bitmap
代码如下: HttpFileCollection httpfiles = context.Request.Files; files = httpfiles[i]; Image im = Image.F ...
-
[转]MSBuild Target Framework and Target Platform
本文转自;https://msdn.microsoft.com/en-us/library/hh264221.aspx A project can be built to run on a targe ...