在第二篇文章《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实现消息的分发机制(三)的更多相关文章

  1. 深入源代码解析Android中的Handler,Message,MessageQueue,Looper

    本文主要是对Handler和消息循环的实现原理进行源代码分析.假设不熟悉Handler能够參见博文< Android中Handler的使用>,里面对Android为何以引入Handler机 ...

  2. Android正在使用Handler实现消息分发机制(零)

    演讲前,AsyncTask文章.我们在最后谈到.AsyncTask它是利用Handler异步消息处理机制,操作结果.使用Message回到主线程,从而执行UI更新线程. 而在我们的日常开发工作,Han ...

  3. Android中的Handler机制

    直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,如下错 误:android.view.ViewRoot$CalledFromWrongThreadException: ...

  4. Android中使用Handler造成内存泄露的分析和解决

    什么是内存泄露?Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用所指向 ...

  5. Android中使用Handler造成内存泄露

    1.什么是内存泄露? Java使用有向图机制,通过GC自动检查内存中的对象(什么时候检查由虚拟机决定),如果GC发现一个或一组对象为不可到达状态,则将该对象从内存中回收.也就是说,一个对象不被任何引用 ...

  6. Android中的Handler的机制与用法详解

    概述: 很多android初学者对android 中的handler不是很明白,其实Google参考了Windows的消息处理机制, 在Android系统中实现了一套类似的消息处理机制.在下面介绍ha ...

  7. android中的Handler和Runnable

    最近在做一个项目,在网络请求时考虑用Handler进行处理,然后就研究了一下Handler和Runnable 首先在看一下java中的Runnable The Runnable interface s ...

  8. 转:Android中的Handler的机制与用法详解

    注:Message类的用法: message的几个参数都可以携带数据,其中arg1与arg2可以携带int类型,what是用户自定义的int型,这样接受者可以了解这个消息的信息. 说明:使用Messa ...

  9. Android中的Handler,以及用Handler延迟执行

    项目中遇到一个情况,先生成文件再上传:但有时候发出指令后上传会不成功,需要再发一次指令方能上传. 猜想是由于文件还没生成就执行「上传」指令了.想到要延时.Android中单纯用currentThrea ...

随机推荐

  1. mumu血压计母亲节“拼团”盛大开幕,百度和厂家创造一个双赢的局面

        在BAT的互联网时代.似乎不论什么新兴产品和服务都不能脱离BAT的支持,作为中国互联网体量最庞大的三家企业.BAT代表的是资源优势.用户优势.品牌优势.因此,一旦脱离BAT的支持,想迅速做大无 ...

  2. rest服务器

    一个轻量级rest服务器   RestServer直接发布数据库为json格式提供方法 RestSerRestServer直接发布数据库为json格式 支持MySQL,SqlServer,Oracle ...

  3. Thread thread2 = new Thread()

    Thread thread2 = new Thread() { @Override public void run() { test.function(); } }; thread1.start(); ...

  4. Java操作memcached(一)

    Memcached事实上,两次Hash算法    第一次hash算法被用于定位Memcached示例    第二次hash算法是底部HashMap中间hash算法 Hash算法      1.依据余数 ...

  5. SQL Server 连接问题-命名管道

    原文:SQL Server 连接问题-命名管道 出自:http://blogs.msdn.com/b/apgcdsd/archive/2011/01/12/sql-server-1.aspx 一.前言 ...

  6. Android开发技巧——实现在图标文本底部导航栏(更新)

    本文参考了导航栏的代码viewpagerindicator实现. 本文介绍了之前版本号qq或者微信,添加文本,实现图标,导航栏的底部. 2014-09-14 13:59:42更新:library的代码 ...

  7. 如何实现Web聊天

    假设你web聊天不知道这件事情,那么最好的方法可能是:openfire+jsjac openfire它是java做开源xmppserver,jsjac它是javascript做开源的Web版本xmpp ...

  8. sqlserver不能直接create table as select

    sqlserver不能直接create table as select 在sqlserver 下想复制一张表的,想到oracle下直接create table xxx as select * from ...

  9. Asp.NET MVC3 使用 SignalR 实现推

    一,简单介绍 Signal 是微软支持的一个执行在 Dot NET 平台上的 html websocket 框架. 它出现的主要目的是实现server主动推送(Push)消息到client页面,这样c ...

  10. Cocos2dx 3.0 过渡篇(二十五)死不了的贪食蛇(触摸版)

    上一篇写的贪食蛇的重力感应控制版,这一篇就讲下触摸控制版吧.额,也不知道写了那个贪食蛇教程究竟有没有获得沈老师的书,假设没有的话,看我不拿西瓜刀砍掉 偶尔E往事 的那啥! 重力版链接:http://b ...