首页 > 程序开发 > 移动开发 > Android >

Android多线程异步任务,在主线程中回调

2017-06-30

Android多线程异步任务,在主线程中回调。在Android中在后台执行多线程异步任务的时候,当异步任务执行成功之后就需要回调主线程,在Android中有很多种回调的方式,我这边自己根据自己开发出的项目,整理出了自己的一个异步回调的工具类

Android多线程异步任务,在主线程中回调

在Android中在后台执行多线程异步任务的时候,当异步任务执行成功之后就需要回调主线程,在Android中有很多种回调的方式,我这边自己根据自己开发出的项目,整理出了自己的一个异步回调的工具类,是基于Handler写出来的,但是比以往的方式使用起来更方便一点:

实现的思路

在自己项目中,使用到了USB协议,整个协议的完成需要自己封装,在走USB协议的时候自己选择的是异步处理,当然Android系统是允许USB协议中的数据发送和接受是在主线程执行的。自己还是觉得把它放在异步任务好一点。在相关的一些初始化操作执行完成之后,这个时候就需要回调,在界面上显示出,我现在和设备所处的状态是什么样子的。此时自己使用Handler写了一个,马上就搞定了,代码也很简单;

使用Handler,让Handler去执行某一个固定的方法,这样就可以,代码如下:

Handler主线程回调

public class TestThread extends Thread {

    private OnMainCallBack mOnMainCallBack;
    private MyHandler mHandler;

    public TestThread(OnMainCallBack mainCallBack){
        this.mOnMainCallBack=mainCallBack;
        mHandler=new MyHandler();
    }

    @Override
    public void run() {
        super.run();
        //*******do something

        //*******线程中的操作执行完了,需要回调通知界面去进行更新
        mHandler.sendMessage(mHandler.obtainMessage(MyHandler.WHAT_ON_MAIN, "更新数据..."));
    }

    private class MyHandler extends Handler{

        public static final int WHAT_ON_MAIN=1;

        public MyHandler() {
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case WHAT_ON_MAIN://在主线程中回调该方法,这样在毁掉中就可以进行相关UI操作
                    if(mOnMainCallBack!=null)mOnMainCallBack.onMainCallBack(msg.obj.toString());
                    break;
            }
        }

    }

    /**主线程回调接口*/
    public interface OnMainCallBack{

        /**回调方法*/
        void onMainCallBack(String data);
    }
}

代码说明

当线程中的run,执行完操作只要需要通知界面去更新数据,这个时候让handler去执行需要回调的方法即可。这样方法回调就在主线程内了,在回调的方法中就可以直接去更新UI界面了

代码分析

这样做确实能实现我们所需要的,但是如果是多线程去执行,需要new 多个像这样的线程去进行异步,岂不是也要new 多个Handler,那我们就把Handler的代码抽出来吧,以免重复的去new。代码如下

抽出的MyHandler代码如下:

public class MyHandler extends Handler{

    public static final int WHAT_ON_MAIN=1;
    private static MyHandler sMyHandler;

    private TestThread.OnMainCallBack mOnMainCallBack;

    public static MyHandler createHandler(TestThread.OnMainCallBack callBack){
        if(sMyHandler==null)sMyHandler=new MyHandler();
        sMyHandler.setCallBack(callBack);
        return sMyHandler;
    }

    private MyHandler() {
        super(Looper.getMainLooper());
    }

    public void setCallBack(TestThread.OnMainCallBack mainCallBack){
        this.mOnMainCallBack=mainCallBack;
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case WHAT_ON_MAIN://在主线程中回调该方法,这样在毁掉中就可以进行相关UI操作
                if(mOnMainCallBack!=null)mOnMainCallBack.onMainCallBack(msg.obj.toString());
                break;
        }
    }
}

代码说明

代码抽出来之后,给了一个单例模式,这样在多线程里就可以被复用了,这样避免了new 多个handler的情况,但是Ne,多线程可能需要执行的业务逻辑不一样,那么回调的方法也会不一样,我们难道需要一个个的像setCallBack(TestThread.OnMainCallBack mainCallBack)这样去重复的去写set方法吗?是不是就很麻烦了,而且这样Handler的解耦性也不够好,要根据不同的业务逻辑去写很多歌setCallBack的方法。其实呢,有一个好的方法能解决这个问题,那就是Java的反射,通过反射的原理去实现你在主线程执行任何方法。对Java反射机制不够了解的可以去看看这篇文章:[http://blog.csdn.net/u013238950/article/details/52164402]

使用反射去执行

在执行反射去调用方法的时候,有几个地方你是要必须能获取到的,一个是该方法的引用、一个是该方法的class、一个是你调用方法的方法名、一个是你调用方法的参数类型以及对于的参数;需要知道这么多的东西,那我们就需要定义一个类去存放这些信息,在执行反射的时候把这个类直接作为参数参入去执行。我这边为了方便写了一个Builder的类,去记录这些信息,在Handler中期反射调用方法。

改良后的MyHandler代码如下:

public class InvokeUtils extends Handler {

    private final int WHAT_ON_MAIN_EXCUTE_METHOD =1;//Handler主线程执行

    private static InvokeUtils sInvoke;

    protected InvokeUtils(){
        super(Looper.getMainLooper());
    }

    public static InvokeUtils getInstance(){
        if(sInvoke ==null) sInvoke =new InvokeUtils();
        return sInvoke;
    }

    /**创建方法执行的builder*/
    public static MethodExcuteBuilder createBuilder(){
        return new MethodExcuteBuilder();
    }


    /**在主线程反射执行方法*/
    public void onMainExcute(MethodExcuteBuilder builder){
        if(builder==null)return;
        this.sendMessage(this.obtainMessage(WHAT_ON_MAIN_EXCUTE_METHOD, builder));
    }

    /**反射执行方法*/
    public void excuteMethod(MethodExcuteBuilder builder){
        try {
            Method m=builder.clazz.getDeclaredMethod(builder.method, builder.parameterTypes);
            m.setAccessible(true);
            m.invoke(builder.objClazz, builder.params);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case WHAT_ON_MAIN_EXCUTE_METHOD://在主线程内去执行方法
                excuteMethod((MethodExcuteBuilder) msg.obj);
                break;
        }
    }

    /**方法执行的builder*/
    public static class MethodExcuteBuilder {

        private Object objClazz;

        private Class clazz;

        private String method;

        private Class[] parameterTypes;

        private Object[] params;

        /**设置调用方法的实体类*/
        public MethodExcuteBuilder setObjClazz(Object objClazz) {
            this.objClazz = objClazz;
            return this;
        }

        /**设置方法的名称*/
        public MethodExcuteBuilder setMethod(String method) {
            this.method = method;
            return this;
        }

        /**设置class*/
        public MethodExcuteBuilder setClazz(Class clazz) {
            this.clazz = clazz;
            return this;
        }

        /**设置方法的参数类型*/
        public MethodExcuteBuilder setParameterTypes(Class... parameterTypes) {
            this.parameterTypes = parameterTypes;
            return this;
        }

        /**设置方法的参数*/
        public MethodExcuteBuilder setParams(Object... params) {
            this.params = params;
            return this;
        }

        private MethodExcuteBuilder(){};

        /**反射执行方法*/
        public void excuteMethod(){
            InvokeUtils.getInstance().excuteMethod(MethodExcuteBuilder.this);
        }

        /**在主线程中反射执行方法*/
        public void onMainExcute(){
            InvokeUtils.getInstance().onMainExcute(MethodExcuteBuilder.this);
        }

    }

}

代码说明

这样记录下了需要反射执行的方法的信息到MethodExcuteBuilder中,为了方便代码书写,我加入了链式调用的方式。在InvokeUtils去调用onMainExcute(MethodExcuteBuilder builder)和excuteMethod(MethodExcuteBuilder builder)去执行需要反射的方法;或者可以在MethodExcuteBuilder中调用excuteMethod()和onMainExcute()去执行需要反射的方法。

代码分析

在使用反射了之后,Handler再也不再受到CallBack的拘束了,使用反射的方式去调用任何CallBack里的任何回调方法。这样实现了解耦的操作,能让自己的代码变得更加的灵活了。

调用Demo如下:

public class TestThread extends Thread {

    private OnMainCallBack mOnMainCallBack;

    public TestThread(OnMainCallBack callBack){
        mOnMainCallBack=callBack;
    }

    @Override
    public void run() {
        super.run();
        //*******do something

        //*******线程中的操作执行完了,需要回调通知界面去进行更新
        //mHandler.sendMessage(mHandler.obtainMessage(MyHandler.WHAT_ON_MAIN, "更新数据..."));

        //使用解耦的方式去进行调用
        InvokeUtils.MethodExcuteBuilder builder=InvokeUtils.createBuilder();
        builder.setObjClazz(mOnMainCallBack)//设置调用方法的类的引用
                .setClazz(OnMainCallBack.class)//设置class
                .setMethod("onMainCallBack")//设置需要调用的方法名
                //设置参数的类型,
                // !!!注意!!!
                //定义的方法参数类型不能为int、boolean等基础数据类型,要写成Integer、Boolean等;
                // 否则无法调用方法
                .setParameterTypes(String.class)
                .setParams("更新数据...");//设置方法需要传入的参数

        //调用方式1
        builder.onMainExcute();//在主线程执行,如果只是想执行改方法调用excuteMethod()即可

        //调用方式2
        //InvokeUtils.getInstance().onMainExcute(builder);
    }

    /**主线程回调接口*/
    public interface OnMainCallBack{

        /**回调方法*/
        void onMainCallBack(String data);
    }
}

如果大家觉得我的代码还存在瑕疵或者自己有更好的方法,希望大家能提出意见,谢谢!

相关文章
最新文章
热点推荐