• 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

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

    尽管仅仅是一个不是非常成熟的想法,但还是希望可以跟大家分享一下,在设计代码架构的时候,可以依据功能,业务需求或者基础框架来进行分层,分块,实现代码的松耦合。

    结束。





  • 相关阅读:
    Linux下安装confluence汉化破解版
    某种可以解决一切问题的方法
    普通平衡树(treap)
    文艺平衡树(splay模板)
    [CQOI2015]任务查询系统
    [NOIP2016]天天爱跑步
    NOI2018_Day1_T1_归程
    Picture
    bzoj3524 Couriers
    bzoj2588 counting on a tree
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4315934.html
Copyright © 2020-2023  润新知