Android 从零开始打造异步处理框架
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/52847872
本文出自【赵彦军的博客】
- 概述
- 封装尝试
- Handler优化
- 线程优化
- 框架使用
- 参考资料
概述
在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 {@Overridepublic 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 {@Overridepublic void run() {super.run();}/*** 任务开始之前调用,运行在主线程*/@MainThreadpublic void onStart(){ }/*** 子线程中调用,运行在子线程* @return*/@WorkerThreadpublic abstract T onDoInBackground() ;/*** 子线程返回的结果,运行在主线程* @param t*/@MainThreadpublic void onResult( T t ){ }
}
另外子线程和主线程通信我们用的是Handler。Handler的初始化工作放在ThreadTask构造函数中完成。
private Handler handler ;public ThreadTask(){handler = new Handler( Looper.getMainLooper()){@Overridepublic 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()){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);//在这里接收子线程发过来的消息onResult((T) msg.obj);}} ;}@Overridepublic void run() {super.run();Message message = Message.obtain() ;message.obj = onDoInBackground() ;handler.sendMessage( message ) ;}/*** 任务开始之前调用,运行在主线程*/@MainThreadpublic void onStart(){ }/*** 子线程中调用,运行在子线程* @return*/@WorkerThreadpublic abstract T onDoInBackground() ;/*** 子线程返回的结果,运行在主线程* @param t*/@MainThreadpublic void onResult( T t ){ }/*** 开始执行*/public void execute(){onStart();start();}
}
如何使用我们写好的框架?
new ThreadTask<String>(){@Overridepublic void onStart() {super.onStart();Log.d( "ThreadTask " , "onStart线程:" + Thread.currentThread().getName() ) ;}@Overridepublic String onDoInBackground() {Log.d( "ThreadTask " , "onDoInBackground线程: " + Thread.currentThread().getName() ) ;//模拟耗时操作try {Thread.sleep( 3000 );} catch (InterruptedException e) {e.printStackTrace();}return "结果返回了";}@Overridepublic 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 );}@Overridepublic 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(){}@Overridepublic void run() {super.run();Message message = Message.obtain() ;message.obj = new ResultData<T>( this , onDoInBackground() ) ;getHandler().sendMessage( message ) ;}/*** 任务开始之前调用,运行在主线程*/@MainThreadpublic void onStart(){ }/*** 子线程中调用,运行在子线程* @return*/@WorkerThreadpublic abstract T onDoInBackground() ;/*** 子线程返回的结果,运行在主线程* @param t*/@MainThreadpublic 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 );}@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void run() {Message message = Message.obtain() ;message.obj = new ResultData<T>( ThreadTask.this , onDoInBackground() ) ;getHandler().sendMessage( message ) ;}});}/*** 任务开始之前调用,运行在主线程*/@MainThreadpublic void onStart(){ }/*** 子线程中调用,运行在子线程* @return*/@WorkerThreadpublic abstract T onDoInBackground() ;/*** 子线程返回的结果,运行在主线程* @param t*/@MainThreadpublic 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 );}@Overridepublic 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>(){@Overridepublic String onDoInBackground() {return "我是线程";}}.execute();
- 方式2
new MyTask().execute();class MyTask extends ThreadTask<String> {@Overridepublic void onStart() {super.onStart();}@Overridepublic String onDoInBackground() {try {//模拟耗时操作Thread.sleep( 2000);} catch (InterruptedException e) {e.printStackTrace();}return "ThreadTask" ;}@Overridepublic void onResult(String s) {super.onResult(s);}}
参考资料
【1】Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
【2】Android 自定义线程池的实战
【3】Java 单例模式
【4】Android Handler、Loop 的简单使用
【5】Android 更新UI的几种方式
Android 从零开始打造异步处理框架相关推荐
- android 学习随笔十二(网络:使用异步HttpClient框架)
使用异步HttpClient框架发送get.post请求 在https://github.com/ 搜索 asyn-http https://github.com/search?utf8=✓& ...
- 从零开始打造自己的PHP框架――第2章
目标 本篇,我们来实现加载控制器.数据查询和页面渲染. 原文地址:http://www.voidking.com/2017/... 加载控制器 控制器 在app目录下,新建ctrl目录,ctrl目录下 ...
- [android] 异步http框架与实现原理
介绍github上的异步http框架android-async-http loopj开发 获取AsyncHttpClient对象,通过new 调用AsyncHttpClient对象的get(url,r ...
- 树莓派 + Home Assistant + HomeKit 从零开始打造个人智能家居系统 篇二:初步配置 Home Assistant 并连接小米设备与 HomeKit
树莓派 + Home Assistant + HomeKit 从零开始打造个人智能家居系统 篇二:初步配置 Home Assistant 并连接小米设备与 HomeKit 通过本篇教程,你将完成对 H ...
- 【秒杀系统】从零开始打造简易秒杀系统(一):防止超卖
前言 大家好,好久不发文章了.(快一个月了- -)最近有很多学习的新知识想和大家分享,但无奈最近项目蛮忙的,很多文章写了一半搁置在了笔记里,待以后慢慢补充发布. 本文主要是通过实际代码讲解,帮助你一步 ...
- 2017 Android GitHub常用热门开源框架汇总
现在 GitHub 上流行的开源库极大地节省了开发者从 0 开发的时间,很多公司和个人都在 GitHub 上开源自己的项目,今天我们就来整理一下 Android 开发中一些非常流行的库,也是我们必须掌 ...
- AsyncQueryHandler 异步查询框架
AsyncQueryHandler简介: 异步的查询操作帮助类,可以处理增删改(ContentProvider提供的数据) 使用场景: 在一般的应用中可以使用ContentProvider去操作数据库 ...
- Android之AsyncTask异步任务详解总结
Android 多线程----AsyncTask异步任务详解 [正文] 本文将讲解一下Android的多线程的知识,以及如何通过AsyncTask机制来实现线程之间的通信. 一.Android当中的多 ...
- Android Glide图片加载框架(三)缓存机制
文章目录 一.缓存简介 二.缓存用法 内存缓存方式 磁盘缓存方式 三.缓存KEY 四.内存缓存 内存缓存流程 五.磁盘缓存 磁盘缓存流程 Android Glide图片加载框架系列文章 Android ...
最新文章
- 【拓扑排序】【bitset】Gym - 101128A - Promotions
- 人脸和性别识别(基于OpenCV)
- 北大OJ百练——3179:最长单词(C语言)
- centos6查看java命令_centos6.5下常见命令和操作
- java nio与io_Java NIO和IO的区别(转)
- 备忘:phalcon的坑
- java 并发测试main方法_java并发编程test之synchronized测试
- saltstack mysql_saltstack学习五:return及入库_MySQL
- 代码管理工具TortoiseGit配置(GIT的客户端)
- ebpf_exporter - Prometheus exporter for custom eBPF metrics
- 监视和调整Linux网络协议栈:接收数据
- Infer.NET——为热爱概率的人准备的库
- 麓山滨江2021高考成绩查询,长沙2021高考成绩排名榜单,长沙各高中高考成绩喜报...
- 在微型计算机中r o m是什么,微机原理试题一
- 学计算机的该不该参加培训机构
- 完美收官!Fortinet Accelerate 2022中国站在北京落幕
- 自然语言生成技术现状调查:核心任务、应用和评估(2)
- 密码学基础:Base64编码
- 华为FreeBuds SE耳机突然没有声音了是怎么回事?
- 拼多多关键词搜索商品接口,拼多多关键词搜索列表接口,宝贝详情页接口,关键词取商品列表接口
热门文章
- mybatis mysql crud_Mybatis实现CRUD操作
- html模块开发模板引擎,一个前端html模板处理引擎(javascript)
- 四个变量的图表怎么做_年终总结必备:Excel双色图表怎么做?数据表达更直观...
- python装饰器常见问题_关于python装饰器的问题
- mysql待办事项表名_SSD8-Ex4待办事项列表答案参考
- 【小白学习PyTorch教程】十七、 PyTorch 中 数据集torchvision和torchtext
- 深度学习和目标检测系列教程 10-300:通过torch训练第一个Faster-RCNN模型
- 四十七、面试前,必须搞懂Java中的线程池ThreadPoolExecutor(上篇)
- leetcode 刷题140 141
- pytorch 和nltk 结合训练的例子