• Android 从零开始打造异步处理框架


    转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/5995752.html
    本文出自【赵彦军的博客】

    概述

    在Android中会使用异步任务来处理耗时操作,避免出现界面卡顿的问题,当然到目前为止可以使用的异步任务框架有很多,比如:

    • 直接 new Thread()
    • 用Android自带的AsyncTask
    • 用RxJava
    • 等等

    今天我们就来自己尝试写一个异步任务处理框架,代码的设计思路参考AsyncTask

    封装尝试

    既然是异步的框架,那么肯定是在子线程中,所以第一步我们用自定义的ThreadTask继承Thread. 并且重写里面的run方法。

    package com.zyj.app;
    
    /**
     * Created by ${zyj} on 2016/10/17.
     */
    
    public class ThreadTask extends Thread {
    
        @Override
        public void run() {
            super.run();
        }
    }
    

    然后子线程需要把处理结果回调给主线程,我们需要定义3个方法:

    • onStart 任务开始之前调用,运行在主线程。可以做显示进度条或者加载动画。
    • onDoInBackground 异步任务执行,运行在子线程。可以做耗时操作。
    • onResult 异步任务处理的结果,运行在主线程。

    onDoInBackground这个方法是要在子类中实现的,所以要写成抽象的方法,那么ThreadTask类自然也要写成抽象类。同时这个方法会返回异步处理结果,这个结果的类型需要写成泛型,以便在子类中灵活运用。

    package com.zyj.app;
    
    import android.support.annotation.MainThread;
    import android.support.annotation.WorkerThread;
    
    /**
     * Created by ${zyj} on 2016/10/17.
     */
    
    public abstract class ThreadTask<T> extends Thread  {
    
        @Override
        public void run() {
            super.run();
        }
    
        /**
         * 任务开始之前调用,运行在主线程
         */
        @MainThread
        public void onStart(){ }
    
        /**
         * 子线程中调用,运行在子线程
         * @return
         */
        @WorkerThread
        public abstract T onDoInBackground() ;
    
        /**
         * 子线程返回的结果,运行在主线程
         * @param t
         */
        @MainThread
        public void onResult( T t ){ }
    }
    
    

    另外子线程和主线程通信我们用的是Handler。Handler的初始化工作放在ThreadTask构造函数中完成。

        private Handler handler ;
    
        public ThreadTask(){
            handler = new Handler( Looper.getMainLooper()){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //在这里接收子线程发过来的消息
                }
            } ;
        }
    

    最后还需要一个execute() 方法启动线程。在启动的前一刻最好调用Onstart方法。

        /**
         * 开始执行
         */
        public void execute(){
            onStart();
            start();
        }
    

    最后一个完整的ThreadTask类是这样的

    package com.zyj.app;
    
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.support.annotation.MainThread;
    import android.support.annotation.WorkerThread;
    
    /**
     * Created by ${zyj} on 2016/10/17.
     */
    
    public abstract class ThreadTask<T> extends Thread  {
    
        private Handler handler ;
    
        public ThreadTask(){
            handler = new Handler( Looper.getMainLooper()){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //在这里接收子线程发过来的消息
                    onResult((T) msg.obj);
                }
            } ;
        }
    
        @Override
        public void run() {
            super.run();
    
            Message message = Message.obtain() ;
            message.obj = onDoInBackground() ;
            handler.sendMessage( message ) ;
        }
    
        /**
         * 任务开始之前调用,运行在主线程
         */
        @MainThread
        public void onStart(){ }
    
        /**
         * 子线程中调用,运行在子线程
         * @return
         */
        @WorkerThread
        public abstract T onDoInBackground() ;
    
        /**
         * 子线程返回的结果,运行在主线程
         * @param t
         */
        @MainThread
        public void onResult( T t ){ }
    
    
        /**
         * 开始执行
         */
        public void execute(){
            onStart();
            start();
        }
    }
    
    

    如何使用我们写好的框架?

    
        new ThreadTask<String>(){
    
            @Override
            public void onStart() {
                super.onStart();
                Log.d( "ThreadTask " , "onStart线程:" + Thread.currentThread().getName() ) ;
            }
    
            @Override
            public String onDoInBackground() {
                Log.d( "ThreadTask " , "onDoInBackground线程: " + Thread.currentThread().getName() ) ;
    
                //模拟耗时操作
                try {
                    Thread.sleep( 3000 );
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "结果返回了";
            }
    
            @Override
            public void onResult(String s) {
                super.onResult(s);
                Log.d( "ThreadTask " , "onResult线程: " + Thread.currentThread().getName()  + " 结果:" + s ) ;
            }
        }.execute();
    
    
    

    运行的结果:

    ThreadTask: onStart线程:main
    ThreadTask: onDoInBackground线程: Thread-229
    ThreadTask: onResult线程: main 结果:结果返回了

    Handler优化

    到目前为止我们的框架初步就封装好了,但是有没有缺点呢,肯定是有的。首先每次创建一个ThreadTask的时候都会创建一个Handler,这显然不是我们想看到的。

    • 要保证Handler的实例的唯一性,可以用单例模式来获取Handler
        /**
         * 单例模式,保证handler只有一个实例
         * @return
         */
        private static Handler getHandler(){
            if ( handler == null ){
                synchronized ( MHandler.class ){
                    if ( handler == null ){
                        handler= new MHandler( Looper.getMainLooper()) ;
                    }
                }
            }
            return handler ;
        }
    
    • MHandler是我们自定义的一个Handler类
        private static class MHandler extends Handler {
    
            public MHandler( Looper looper ){
                super( looper );
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //在这里接收子线程发过来的消息
                ResultData resultData = (ResultData) msg.obj;
                resultData.threadTask.onResult( resultData.data );
            }
        }
    
    • ResultData是一个消息实体
      /**
         * handler发送数据的实体
         * @param <Data>
         */
        private static class ResultData<Data>{
            ThreadTask threadTask ;
            Data data ;
            public ResultData( ThreadTask threadTask  ,Data data  ){
                this.threadTask = threadTask ;
                this.data = data ;
            }
        }
    
    • 一个完整的代码实例
    package com.zyj.app;
    
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.support.annotation.MainThread;
    import android.support.annotation.WorkerThread;
    
    /**
     * Created by ${zyj} on 2016/10/17.
     */
    
    public abstract class ThreadTask<T> extends Thread  {
    
        private static Handler handler ;
    
        public ThreadTask(){
        }
    
        @Override
        public void run() {
            super.run();
            Message message = Message.obtain() ;
            message.obj = new ResultData<T>( this , onDoInBackground() ) ;
            getHandler().sendMessage( message ) ;
        }
    
        /**
         * 任务开始之前调用,运行在主线程
         */
        @MainThread
        public void onStart(){ }
    
        /**
         * 子线程中调用,运行在子线程
         * @return
         */
        @WorkerThread
        public abstract T onDoInBackground() ;
    
        /**
         * 子线程返回的结果,运行在主线程
         * @param t
         */
        @MainThread
        public void onResult( T t ){ }
    
    
        /**
         * 开始执行
         */
        public void execute(){
            onStart();
            start();
        }
    
        /**
         * 单例模式,保证handler只有一个实例
         * @return
         */
        private static Handler getHandler(){
            if ( handler == null ){
                synchronized ( MHandler.class ){
                    if ( handler == null ){
                        handler= new MHandler( Looper.getMainLooper()) ;
                    }
                }
            }
            return handler ;
        }
    
        private static class MHandler extends Handler {
    
            public MHandler( Looper looper ){
                super( looper );
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //在这里接收子线程发过来的消息
                ResultData resultData = (ResultData) msg.obj;
                resultData.threadTask.onResult( resultData.data );
            }
        }
    
        /**
         * handler发送数据的实体
         * @param <Data>
         */
        private static class ResultData<Data>{
            ThreadTask threadTask ;
            Data data ;
            public ResultData( ThreadTask threadTask  ,Data data  ){
                this.threadTask = threadTask ;
                this.data = data ;
            }
        }
    }
    
    

    到现在已经解决了Handler多次创建的问题,那么这个ThreadTask本质上还是新建线程来运行异步任务,为了避免不断的创建线程,所以还需要一个线程池。

    线程优化

    • 首选定义一个线程池,默认最大10个线程。
        /**
         * 线程池,创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
         */
        private static ExecutorService executorService = Executors.newFixedThreadPool( 15 ) ;
    
    • 修改run()方法。
        private void run() {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    Message message = Message.obtain() ;
                    message.obj = new ResultData<T>( ThreadTask.this , onDoInBackground() ) ;
                    getHandler().sendMessage( message ) ;
                }
            });
        }
    
    • execute() 方法
        /**
         * 开始执行
         */
        public void execute(){
            onStart();
            run();
        }
    
    • 完整的代码实例
    package com.zyj.app;
    
    import android.os.Handler;
    import android.os.Looper;
    import android.os.Message;
    import android.support.annotation.MainThread;
    import android.support.annotation.WorkerThread;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * Created by ${zyj} on 2016/10/17.
     */
    
    public abstract class ThreadTask<T>  {
    
        private static Handler handler ;
    
        /**
         * 线程池,创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
         */
        private static ExecutorService executorService = Executors.newFixedThreadPool( 15 ) ;
    
        public ThreadTask(){
    
        }
    
        private void run() {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    Message message = Message.obtain() ;
                    message.obj = new ResultData<T>( ThreadTask.this , onDoInBackground() ) ;
                    getHandler().sendMessage( message ) ;
                }
            });
        }
    
        /**
         * 任务开始之前调用,运行在主线程
         */
        @MainThread
        public void onStart(){ }
    
        /**
         * 子线程中调用,运行在子线程
         * @return
         */
        @WorkerThread
        public abstract T onDoInBackground() ;
    
        /**
         * 子线程返回的结果,运行在主线程
         * @param t
         */
        @MainThread
        public void onResult( T t ){ }
    
    
        /**
         * 开始执行
         */
        public void execute(){
            onStart();
            run();
        }
    
        /**
         * 单例模式,保证handler只有一个实例
         * @return
         */
        private static Handler getHandler(){
            if ( handler == null ){
                synchronized ( MHandler.class ){
                    if ( handler == null ){
                        handler= new MHandler( Looper.getMainLooper()) ;
                    }
                }
            }
            return handler ;
        }
    
        private static class MHandler extends Handler {
    
            public MHandler( Looper looper ){
                super( looper );
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                //在这里接收子线程发过来的消息
                ResultData resultData = (ResultData) msg.obj;
                resultData.threadTask.onResult( resultData.data );
            }
        }
    
        /**
         * handler发送数据的实体
         * @param <Data>
         */
        private static class ResultData<Data>{
            ThreadTask threadTask ;
            Data data ;
            public ResultData( ThreadTask threadTask  ,Data data  ){
                this.threadTask = threadTask ;
                this.data = data ;
            }
        }
    }
    
    

    框架使用

    • 方式1
            new ThreadTask<String>(){
    
                @Override
                public String onDoInBackground() {
                    return "我是线程";
                }
            }.execute();
    
    • 方式2
        new MyTask().execute();
        
        class MyTask extends ThreadTask<String> {
    
            @Override
            public void onStart() {
                super.onStart();
            }
    
            @Override
            public String onDoInBackground() {
                try {
                    //模拟耗时操作
                    Thread.sleep( 2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "ThreadTask" ;
            }
    
            @Override
            public void onResult(String s) {
                super.onResult(s);
            }
        }
    

    参考资料

    【1】Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
    【2】Android 自定义线程池的实战
    【3】Java 单例模式
    【4】Android Handler、Loop 的简单使用
    【5】Android 更新UI的几种方式

  • 相关阅读:
    让x86的android模拟器能模拟arm架构系统
    婴儿补充微量元素
    asterisk 能打电话的配置
    SIP协议错误代码大全
    asterisk错误排查
    asterisk帮助与国内论坛
    win10 只要打开文件对话框就卡死解决方法
    分享到朋友圈实现
    跳转前暂停几秒js如何实现
    Github css加载失败,样式混乱解决办法
  • 原文地址:https://www.cnblogs.com/zhaoyanjun/p/5995752.html
Copyright © 2020-2023  润新知