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

这样,我们就能够将业务逻辑和数据操作给分开了,实现了对功能编程。

虽然只是一个不是很成熟的想法,但还是希望能够跟大家分享一下,在设计代码架构的时候,能够根据功能,业务需求或者基础框架来进行分层,分块,实现代码的松耦合。

结束。

时间: 2024-12-24 14:46:21

Android中利用Handler实现消息的分发机制(三)的相关文章

Android中利用Handler实现消息的分发机制(零)

在之前一篇介绍AsyncTask的文章中,我们在最后讲到,AsyncTask是利用Handler的消息异步处理机制,将操作结果,利用Message传回主线程,从而进行UI线程的更新的. 而在我们日常的开发工作中,Handler也是我们经常使用的类之一,那么Handler的主要作用是什么? Handler 的主要作用就是对消息(消息可以是我们想做的一些UI更新,也可以是其他的一些不可见的操作,如操作数据库等)的异步处理机制,而相信大家都了解异步的概念. 简单地说一下: 1)从程序的角度来看,就是当

Android中利用Handler实现消息的分发机制(二)

在这篇文章开始前,我们先总结一下前两篇文章中关于Handler, Looper和MessageQueue等的一些关键点: 0)在线程中创建Handler之前,必须先调用Looper.prepare(), 创建一个线程局部变量Looper,然后调用Looper.loop() 进入轮循. 1)当Handler创建之后,就可以调用Handler的sendMessageAtTime方法发送消息,而实际上是调用MessageQueue的enqueueMessage方法,将对应的消息放入消息队列. 2)每一

Android中利用Handler实现消息的分发机制(一)

上一篇文章,我们讲到在调用Handler的sendMessage方法时,最终我们会进入到一个叫 sendMessageAtTime的方法,如下: public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMess

Android中使用Handler(消息机制)造成内存泄露的分析和解决

问题描述: Handler 内部类持有 外部类Activity的引用,如果Activity退出而Handler还有延迟处理的消息没有处理完,会导致Activity不能回收,反复如此会导致内存泄露. 解决方案: 1.onDestroy时清除消息. mHandler.removeCallbacksAndMessages(null); // 参数为null时会清除所有消息. 2.声明Handler为static并持有Activity的弱引用. public class MainActivity ext

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

本文主要是对Handler和消息循环的实现原理进行源码分析,如果不熟悉Handler可以参见博文< Android中Handler的使用>,里面对Android为何以引入Handler机制以及如何使用Handler做了讲解. 概括来说,Handler是Android中引入的一种让开发者参与处理线程中消息循环的机制.我们在使用Handler的时候与Message打交道最多,Message是Hanlder机制向开发人员暴露出来的相关类,可以通过Message类完成大部分操作Handler的功能.但

Android中的Handler

当我们在处理下载或是其他需要长时间执行的任务时,如果直接把处理函数放在Activity的OnCreate或是OnStart中,会导致执行过程中整个Activity无响应,如果时间过长,程序就会挂掉.Handler就是把这些功能放到一个当初的线程里执行,与Activity互不影响. 一.Handler的定义:  Handler主要接收子线程发送的数据, 并用此数据配合主线程更新UI,用来跟UI主线程交互用.比如可以用handler发送一个message,然后在handler的线程中来接收.处理该消

Android中的Handler的具体用法

Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行.Android利用Handler来实现UI线程的更新的. Handler是Android中的消息发送器,其在哪个Activity中创建就属于且紧紧属于该Activity.还可以说其在哪个线程中new的,就是那个线程的Handler. Handler的定义: 主要接受子线程发送的数据, 并用此数据配合主线程更新UI. 解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的U

Android中的Handler机制

直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,如下错 误:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.翻译过来就是:只有创建这个控件的线程才能去更新该控件的内容. 所有的UI线程要去负责View的创建并且维护它,例如更新冒个TextView的显示,都必

Android中的Handler, Looper, MessageQueue和Thread

Android中的Handler, Looper, MessageQueue和Thread 前几天,和同事探讨了一下Android中的消息机制,探究了消息的发送和接收过程以及与线程之间的关系.虽然我们经常使用这些基础的东西,但对于其内部原理的了解,能使我们更加容易.合理地架构系统,并避免一些低级错误. 对于这部分的内容,将分成4小节来描述: 1.职责与关系 2.消息循环 3.线程与更新 4.几点小结 ------------------------------------------------