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 ... 
随机推荐
- JAVA基础实例(三)--排序
			冒泡排序 是一种简单的排序算法.它反复地走訪过要排序的数列,一次比較两个元素.假设他们的顺序错误就把他们交换过来.走訪数列的工作是反复地进行直到没有再须要交换,也就是说该数列已经排序完毕. 这个算法的 ... 
- 实现一个简单的boot
			1.汇编语言.分别汇编器和链接as86和ld86.码如下面: .globl begtext,begdata,begbss,endtext,enddata,endbss .text begtext: . ... 
- Visual Studio 2015使用EF6的CodeFirstFromDB模式操作Sqlite数据库时Provider问题
			传送门 什么是CodeFristFromDB 问题:查询数据是遇到 “/”应用程序中的服务器错误. No Entity Framework provider found for the ADO.NET ... 
- 关于sql中去换行符的问题
			今天要用bootstrap开发一个网页,要使用到JSON,但是JSON的格式不正确,然后在http://www.bejson.com/[Be JSON]中测试了一下JSON. 发现JSON中多了一个换 ... 
- 设计模式之空对象(Null Object)模式
			通过引用Null Object,用于取消业务逻辑中对对象的为空推断 类图: Nullable: package com.demo.user; public interface Nullable { b ... 
- HDU 1198 Farm Irrigation (并检查集合 和 dfs两种实现)
			Farm Irrigation Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ... 
- groovy install,gvm,groovysh简述(转)
			1.1 安装Groovy Groovy主页:http://www.groovy-lang.org 确保本地系统安装了Java 1.1.1 在Windows系统上安装Groovy 1.创建环境变量GRO ... 
- Codeforces 479E Riding in a Lift(dp)
			题目链接:Codeforces 479E Riding in a Lift 题目大意:有一栋高N层的楼,有个无聊的人在A层,他喜欢玩电梯,每次会做电梯到另外一层.可是这栋楼里有个秘 密实验室在B层,所 ... 
- cocos2d-x注意事项(十)Lua发展飞机战争-4-创建主角
			二战中被称为二战飞机飞机,当然,以飞机作业.这是一个游戏,我们必须加入一个飞机--这是我们的英雄. 首先创建一个层(PlaneLayer)要显示飞机.然后,create飞机初始化方法 module(& ... 
- 多普勒失真信号采样Matlab模拟分析
			多普勒失真信号采样Matlab模拟分析 方案 水声通信指的是使用声信号在水中数据传输. 相对而言.电磁信号在水中吸收严重衰减过快,光信号受水中悬浮颗粒的影响,也无法完毕远距离传输. 这两种信号的传播距 ... 
