在第二篇文章《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. JAVA基础实例(三)--排序

    冒泡排序 是一种简单的排序算法.它反复地走訪过要排序的数列,一次比較两个元素.假设他们的顺序错误就把他们交换过来.走訪数列的工作是反复地进行直到没有再须要交换,也就是说该数列已经排序完毕. 这个算法的 ...

  2. 实现一个简单的boot

    1.汇编语言.分别汇编器和链接as86和ld86.码如下面: .globl begtext,begdata,begbss,endtext,enddata,endbss .text begtext: . ...

  3. Visual Studio 2015使用EF6的CodeFirstFromDB模式操作Sqlite数据库时Provider问题

    传送门 什么是CodeFristFromDB 问题:查询数据是遇到 “/”应用程序中的服务器错误. No Entity Framework provider found for the ADO.NET ...

  4. 关于sql中去换行符的问题

    今天要用bootstrap开发一个网页,要使用到JSON,但是JSON的格式不正确,然后在http://www.bejson.com/[Be JSON]中测试了一下JSON. 发现JSON中多了一个换 ...

  5. 设计模式之空对象(Null Object)模式

    通过引用Null Object,用于取消业务逻辑中对对象的为空推断 类图: Nullable: package com.demo.user; public interface Nullable { b ...

  6. HDU 1198 Farm Irrigation (并检查集合 和 dfs两种实现)

    Farm Irrigation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  7. groovy install,gvm,groovysh简述(转)

    1.1 安装Groovy Groovy主页:http://www.groovy-lang.org 确保本地系统安装了Java 1.1.1 在Windows系统上安装Groovy 1.创建环境变量GRO ...

  8. Codeforces 479E Riding in a Lift(dp)

    题目链接:Codeforces 479E Riding in a Lift 题目大意:有一栋高N层的楼,有个无聊的人在A层,他喜欢玩电梯,每次会做电梯到另外一层.可是这栋楼里有个秘 密实验室在B层,所 ...

  9. cocos2d-x注意事项(十)Lua发展飞机战争-4-创建主角

    二战中被称为二战飞机飞机,当然,以飞机作业.这是一个游戏,我们必须加入一个飞机--这是我们的英雄. 首先创建一个层(PlaneLayer)要显示飞机.然后,create飞机初始化方法 module(& ...

  10. 多普勒失真信号采样Matlab模拟分析

    多普勒失真信号采样Matlab模拟分析 方案 水声通信指的是使用声信号在水中数据传输. 相对而言.电磁信号在水中吸收严重衰减过快,光信号受水中悬浮颗粒的影响,也无法完毕远距离传输. 这两种信号的传播距 ...