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的几种方式
Android 从零开始打造异步处理框架的更多相关文章
- Android Native层异步消息处理框架
*本文系作者工作学习总结,尚有不完善及理解不恰当之处,欢迎批评指正* 一.前言 在NuPlayer中,可以发现许多类似于下面的代码: //============================== ...
- Android 使用图片异步载入框架Universal Image Loader的问题
使用的Jar包 问题: optionsm = new DisplayImageOptions.Builder() .displayer(new RoundedBitmap ...
- android 学习随笔十二(网络:使用异步HttpClient框架)
使用异步HttpClient框架发送get.post请求 在https://github.com/ 搜索 asyn-http https://github.com/search?utf8=✓& ...
- Android 异步查询框架AsyncQueryHandler的使用
AsyncQueryHandler简介: 异步的查询操作帮助类,可以处理增删改(ContentProvider提供的数据) 使用场景: 在一般的应用中可以使用ContentProvider去操作数据库 ...
- Android异步任务处理框架AsyncTask源代码分析
[转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 引言 在平时项目开发中难免会遇到异步耗时的任务(比方最常见的网络请求).遇到这样的问题.我 ...
- android异步Http框架
首先在GitHub上下载异步Http框架代码以及相关文档: 将jar包放入lib包中即可: 接下来分别实现get.post.文件上传功能实现: 代码实现如下: AsyncHttpClient clie ...
- [android] 异步http框架与实现原理
介绍github上的异步http框架android-async-http loopj开发 获取AsyncHttpClient对象,通过new 调用AsyncHttpClient对象的get(url,r ...
- 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发
掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...
- 2015最流行的Android组件、工具、框架大全
Android 是目前最流行的移动操作系统之一. 随着新版本的不断发布, Android的功能也日益强大, 涌现了很多流行的应用程序, 也催生了一大批的优秀的组件. 本文试图将目前流行的组件收集起来以 ...
随机推荐
- 学习笔记 :DrawText
最近在做一个TStringGrid的自绘处理,在画文字处理上遇到了高度的计算问题.后来经过一段时间还是找到了一些方法: 1.使用TLabel 这个方法是有点绕路的,方法倒是简单,就是使用AutoSiz ...
- 带你一分钟理解闭包--js面向对象编程
上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...
- Redis集群搭建与简单使用
介绍安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都是 CentOS ,一台 ...
- java的继承练习
看程序写结果: A:一个类的静态代码块,构造代码块,构造方法的执行流程 静态代码块 > 构造代码块 > 构造方法 B:静态的内容是随着类的加载而加载 静态代码块的内 ...
- xamarin MasterDetailPage点击Master时卡顿现象
在很多项目中经常会使用到MasterDetailPage的布局方式,而且一般做为主页面来开发,在开发中,发现一个并不算Bug的问题,但是却发生了,以此记录下来,方便大家探讨. 现象是这样的,我开发了一 ...
- Android开发学习之路-Git的极简教程?
Git是一个代码版本管理工具,也就是允许我们的一个项目拥有多个版本,这样我们可以随心所欲的修改我们的代码,如果出现问题,可以回退到某一个提交点.如果你还在用一堆堆注释来更新你的代码,那么可以尝试一下G ...
- 打印Lua的Table对象
小伙伴们再也不用为打印lua的Table对象而苦恼了, 本人曾也苦恼过,哈哈 不过今天刚完成了这个东西, 以前在网上搜过打印table的脚本,但是都感觉很不理想,于是,自己造轮子了~ 打印的效果,自己 ...
- iOS-----正则表达式的基础语法
正则表达式简单语法总结 一.什么是正则表达式 从概念上来说,正则表达式也是一门小巧而精炼的语言,它可以用来简化检索特定的字符串,替换特定字符等功能,有许多开发语言工具,都内嵌支持正则表达式.那么一个正 ...
- [原创]关于ORACLE的使用入门
Oracle===============================数据库:Oracle------>甲骨文(Oracle) 49+%DB2---------->IBM 49+%Sq ...
- springboot(八):RabbitMQ详解
RabbitMQ 即一个消息队列,主要是用来实现应用程序的异步和解耦,同时也能起到消息缓冲,消息分发的作用. 消息中间件在互联网公司的使用中越来越多,刚才还看到新闻阿里将RocketMQ捐献给了apa ...