转载请标明出处: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 从零开始打造异步处理框架的更多相关文章

  1. Android Native层异步消息处理框架

     *本文系作者工作学习总结,尚有不完善及理解不恰当之处,欢迎批评指正* 一.前言 在NuPlayer中,可以发现许多类似于下面的代码: //============================== ...

  2. Android 使用图片异步载入框架Universal Image Loader的问题

    使用的Jar包 问题:        optionsm = new DisplayImageOptions.Builder()         .displayer(new RoundedBitmap ...

  3. android 学习随笔十二(网络:使用异步HttpClient框架)

    使用异步HttpClient框架发送get.post请求 在https://github.com/ 搜索 asyn-http https://github.com/search?utf8=✓& ...

  4. Android 异步查询框架AsyncQueryHandler的使用

    AsyncQueryHandler简介: 异步的查询操作帮助类,可以处理增删改(ContentProvider提供的数据) 使用场景: 在一般的应用中可以使用ContentProvider去操作数据库 ...

  5. Android异步任务处理框架AsyncTask源代码分析

    [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 引言 在平时项目开发中难免会遇到异步耗时的任务(比方最常见的网络请求).遇到这样的问题.我 ...

  6. android异步Http框架

    首先在GitHub上下载异步Http框架代码以及相关文档: 将jar包放入lib包中即可: 接下来分别实现get.post.文件上传功能实现: 代码实现如下: AsyncHttpClient clie ...

  7. [android] 异步http框架与实现原理

    介绍github上的异步http框架android-async-http loopj开发 获取AsyncHttpClient对象,通过new 调用AsyncHttpClient对象的get(url,r ...

  8. 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发

    掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...

  9. 2015最流行的Android组件、工具、框架大全

    Android 是目前最流行的移动操作系统之一. 随着新版本的不断发布, Android的功能也日益强大, 涌现了很多流行的应用程序, 也催生了一大批的优秀的组件. 本文试图将目前流行的组件收集起来以 ...

随机推荐

  1. EF里Guid类型数据的自增长、时间戳和复杂类型的用法

    通过前两章Lodging和Destination类的演示,大家肯定基本了解Code First是怎么玩的了,本章继续演示一些很实用的东西.文章的开头提示下:提供的demo为了后面演示效果,前面代码有些 ...

  2. 用Go实现的简易TCP通信框架

    接触到GO之后,GO的网络支持非常令人喜欢.GO实现了在语法层面上可以保持同步语义,但是却又没有牺牲太多性能,底层一样使用了IO路径复用,比如在LINUX下用了EPOLL,在WINDOWS下用了IOC ...

  3. ASP.NET MVC 描述类型(一)

    ASP.NET MVC 描述类型(一) 前言 在前面的好多篇幅中都有提到过ControllerDescriptor类型,并且在ASP.NET MVC 过滤器(一)篇幅中简单的描述过,今天我们就来讲一下 ...

  4. TODO:Golang语言TCP/UDP协议重用地址端口

    TODO:Golang语言TCP/UDP协议重用地址端口 这是一个简单的包来解决重用地址的问题. go net包(据我所知)不允许设置套接字选项. 这在尝试进行TCP NAT时尤其成问题,其需要在同一 ...

  5. 给 Android 研发的一些的建议

    作为应用程序开发人员,我们需要注意在开发应用程序时的一些问题. 这些问题的安全级别是取决于应用程序的类型和使用域. 在这里列举了一些我们在开发中需要注意的一些问题: 开发日志输出相关: 1. 不要在 ...

  6. 游戏服务器菜鸟之C#初探四游戏服务

    经过多次折腾之后,在一次进行了一次重大的重构,去解决问题 主要重构如下 1.将原来的单一协议修改多协议进行,一些查询.认证的功能都采用HTTP进行,避免全部采用TCP链接资源的消耗: 2.原来单一的部 ...

  7. linux tree 命令

    使用cmder确实是方便了很多,想看命令帮助信息: $ help tree 以图形显示驱动器或路径的文件夹结构. TREE [drive:][path] [/F] [/A] /F 显示每个文件夹中文件 ...

  8. canvas第一天

    第一次接触canvas,<canvas></canvas>是html5出现的新标签,IE9开始支持,像所有的dom对象一样它有自己本身的属性.方法和事件,其中就有绘图的方法,j ...

  9. 解析大型.NET ERP系统 通用附件管理功能

    大型系统具备一个通用的附件管理功能,对于单据中无法清晰表达的字段,用一个附件图片或附件文档表示是最好的方法了.比如物料清单附加一张CAD图纸,销售订单评审功能中附加客户的各种表格,通用附件功能对系统起 ...

  10. ASP.NET MVC5+EF6+EasyUI 后台管理系统(49)-工作流设计-我的申请

    系列目录 提交一个表单后 我们需要一个管理的列表.我的申请,我的申请包含了提交内容的列表状态 状态分:过期,未审核,审核通过,驳回,废弃 列表对应代码 @using App.Admin; @using ...