在第二篇文章《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 : 110-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 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

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

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

结束。





更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. 拥抱Android(安卓)Studio:从Eclipse到Android(安卓)Studio的完美
  3. android 如何使用SAX解析XML
  4. 深入Android的消息机制源码详解~Handler,MessageQueue与Looper关
  5. Android应用盈利广告平台的嵌入方法详解
  6. Android(安卓)自定义音乐播放器实现
  7. Handle机制详解
  8. android每日一问1【2011-09-06】
  9. 巨佬Jake Wharton谈Android对Java 8的支持

随机推荐

  1. Ashmem笔记
  2. android Studio Error: 前言中不允许有内
  3. onConfigurationChanged会重新 OnCreate
  4. div+css命名规范 嫁接android xml命名
  5. 我的Android进阶之旅------>Android之选
  6. android-电话拨号器&点击事件四种写法
  7. android 问题汇总系列之四
  8. Android 响应式编程框架 - RxJava2(二)基础
  9. Android开机自启动程序设置及控制方法思
  10. Android Studio中genymotion安装方法