轉載請标明出處: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的幾種方式