AsyncTask 详解

本文将先阐述AsyncTask的概念、特征及基本用法,之后再以一个实例来验证实际的应用。

 

AsyncTask

AsyncTask  -- 直接继承与Object类 在API-3中定义

一 概述:
  AsyncTask 目的是为了更方便容易的使用UI 线程,它允许在UI线程中执行后台操作并将后台处理的结果返回给UI线程,而不需要繁琐的开启一个线程或者Handler来处理后台操作。
  AsyncTask 是一个综合Thread 和 Handler的辅助类,并不是通用线程框架的一部分。AsyncTask 是短期后台操作的理想选择(最多几秒钟),如果你需要线程长时间的保持运行,强烈建议你使用 java.util.concurrent 包提供的各种API以满足你的需求,比如:Executor, ThreadPoolExecutor and FutureTask.
  异步任务是指在后台运行的一些列运算,并将结果反馈给UI线程,异步任务有三个泛型输入:输入参数(param)、处理进度(Progress)、处理结果(results)。大致可分为四个步骤:预处理(onPreExecute)、后台处理(doInBackground)、更新处理进度(onProgressUpdate )、处理完成(onPostExecute)

PS:如果需要了解更多关于任务和线程的相关信息,可以阅读与进程和想成相关的开发指南

二 用法:
 AsyncTask 是抽象类,所以必须继承才能使用。子类至少要重写doInBackground 这个方法,大多数情况也会重写onPostExecute,下面是一个继承AsyncTask的实例:
 

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
	protected Long doInBackground(URL... urls) {
		int count = urls.length;
		long totalSize = 0;
		for (int i = 0; i < count; i++) {
			totalSize += Downloader.downloadFile(urls[i]);
			publishProgress((int) ((i / (float) count) * 100));
			// Escape early if cancel() is called
			if (isCancelled())
				break;
		}
		return totalSize;
	}

	protected void onProgressUpdate(Integer... progress) {
		setProgressPercent(progress[0]);
	}

	protected void onPostExecute(Long result) {
		showDialog("Downloaded " + result + " bytes");
	}
}


 只要子类建立好了之后,运行这个DownloadFilesTask非常容易:
 new DownloadFilesTask().execute(url1, url2, url3);
 
AsyncTask的三个泛型
一个异步任务使用到的泛型如下:
1.Param ,用于指定任务执行前的参数类型
2.Progress, 用于指定后台计算任务的百分比数值类型
3.Result,用于指定后台计算结果的数据类型

PS:并不是所有的泛型都需要指定,如果不需要使用泛型可以使用void标识:
 private class MyTask extends AsyncTask<Void, Void, Void> { ... }

AsyncTask 中的四个步骤:
1.onPreExecute() -->在UI线程中执行(启动AsyncTask时调用,无需在程序中显示的调用该API),这步主要是完成一些基本的设置行为,比如(为后台处理进度)实例化一个UI界面
2.doInBackground(Params...)--> 由后台线程调用,当执行完onPreExecute 后会立即执行该API,此步骤主要是用于执行一些后台的计算行为,启动AsyncTask时所带的参数将传递给该API,此API return的参数将传递给最后一步(onPostExecute),在这一步的时候可以调用 publishProgress(Progress...)将数据传递给onProgressUpdate以告知当前的处理进度。
3.onProgressUpdate(Progress...) --> 在UI线程中执行,当收到来自 publishProgress(Progress...)的消息后,可以根据需求更新UI界面上的动画来告知用户当前的处理进度。
4.onPostExecute(Result)--> 在UI线程中调用(非显示的调用,由线程自动完成)处理的结果会被传递到此API,可用于更新处理的结果

取消任务:
AsyncTask 在运行的过程中也可以调用AsyncTask对象的cancel(booean)方法取消当前的任务,当调用此方法后,会等待doInBackground(Object[]) 执行完成,后再调用 onCancelled(Object)方法而不会再调用onPostExecute(Object)。如果主线程需要尽快的检查当前的任务是否被取消可以使用isCancelled() 做周期性的检查
PS:cancel的入参可以决定是否终端后台任务线程,后台任务线程捕获到中断异常之后会决定如何处理。

内存可观察性:
AsyncTask 中所有的回调都是同步的,以保证线程的安全性。如下面的使用方式无需使用synchronizations即可保证线程安全:
·在constructor或者onPreExecute中设置类属性,然后在doInBackground中引用这些属性
·在doInBackground中设置类属性,然后在onProgressUpdate和onPostExecute中引用那个这些属性。

执行顺序:
AsyncTask在第一次发布的时候,是在后台的一个单一线程中串行执行的。从DONUT(android 1.6)开始,AsyncTask被放在线程池中被允许并发执行。从Android 3.0/3.1/3.2 Honeycomb(蜂巢)版本后,为了避免并发执行带来的常见的应用程序错误。

如果你确实需要并发执行,你可以将THREAD_POOL_EXECUTOR作为参数传入executeOnExecutor(java.util.concurrent.Executor, Object[])来执行AsyncTask。

 

三、应用实例

1.界面布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/TextView01"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <ProgressBar
        android:id="@+id/ProgressBar02"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/Button_Start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Update progressbar" />

    <Button
        android:id="@+id/Button_Stop"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Stop update" />

</LinearLayout>

 

2.Activity

package com.sunmedia.androidasynctask;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {
	private ProgressBar progressBar;
	private Button btStart;
	private Button btStop;
	private TextView textView;
	ProgressBarAsyncTask mAsyncTask;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        btStart = (Button)findViewById(R.id.Button_Start);
        btStop = (Button)findViewById(R.id.Button_Stop);
        progressBar = (ProgressBar)findViewById(R.id.ProgressBar02);
        textView = (TextView)findViewById(R.id.TextView01);
        
        
        btStart.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				mAsyncTask = new ProgressBarAsyncTask(textView, progressBar);
				mAsyncTask.execute(1000);
			}
		});
        
        btStop.setOnClickListener(new OnClickListener() {
        	
        	@Override
        	public void onClick(View v) {
        		Log.d("test", "btStop onclick");
        		if(mAsyncTask != null){
        			boolean b = mAsyncTask.cancel(false);
        			System.out.println(b);
        		}
        	}
        });
    }
}


3.AsyncTask

package com.sunmedia.androidasynctask;

import android.os.AsyncTask;
import android.util.Log;
import android.widget.ProgressBar;
import android.widget.TextView;

/**
 * 生成该类的对象,并调用execute方法之后 首先执行的是onProExecute方法 其次执行doInBackgroup方法
 * 
 */
public class ProgressBarAsyncTask extends AsyncTask<Integer, Integer, String> {

	private TextView textView;
	private ProgressBar progressBar;

	public ProgressBarAsyncTask(TextView textView, ProgressBar progressBar) {
		super();
		this.textView = textView;
		this.progressBar = progressBar;
	}

	/**
	 * 这里的Integer参数类型对应AsyncTask中的第一个泛型参数 这里的String返回值对应AsyncTask的第三个泛型参数
	 * 该方法并不运行在UI线程当中,主要用于异步操作,所有在该方法中不能对UI当中的空间进行设置和修改
	 * 但是可以调用publishProgress方法触发onProgressUpdate对UI进行操作
	 */
	@Override
	protected String doInBackground(Integer... params) {
		CalOperator calOperator = new CalOperator();
		int i = 0;
		for (i = 10; i <= 100; i += 10) {
			Log.d("test", "doInBackground,name:"
					+ Thread.currentThread().getName());
			if (calOperator.operator() != -1) {
				publishProgress(i);
			} else {
				break;
			}
		}
		return i + params[0].intValue() + "";
	}

	/**
	 * 这里的String参数类型对应AsyncTask中的第三个泛型参数
	 * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置
	 */
	@Override
	protected void onPostExecute(String result) {
		Log.d("test", "onPostExecute,name:" + Thread.currentThread().getName());
		textView.setText("异步操作执行结束" + result);
	}

	// 该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
	@Override
	protected void onPreExecute() {
		Log.d("test", "onPreExecute,name:" + Thread.currentThread().getName());
		textView.setText("开始执行异步线程");
	}

	/**
	 * 这里的Intege参数类型对应AsyncTask中的第二个泛型参数
	 * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
	 * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作
	 */
	@Override
	protected void onProgressUpdate(Integer... values) {
		Log.d("test", "onProgressUpdate,name:"
				+ Thread.currentThread().getName());
		int vlaue = values[0];
		progressBar.setProgress(vlaue);
	}

	@Override
	protected void onCancelled() {
		Log.d("test", "onCancelled,name:" + Thread.currentThread().getName());
		super.onCancelled();
	}
}


4.模拟实际任务

package com.sunmedia.androidasynctask;


//模拟计算环境
public class CalOperator {
	
	public int operator(){
		int i = 0;
		try {
			//休眠1秒
			Thread.sleep(1000);
			
		} catch (InterruptedException e) {
			e.printStackTrace();
			//捕获到中断异常后退出
			i = -1;
		}
		return i;
	}

}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值