介绍:
中文API http://www.cnblogs.com/over140/archive/2011/02/17/1956634.html
一、结构
public abstract class AsyncTask extends Object
java.lang.Object
android.os.AsyncTask<Params, Progress, Result>
二、类概述
AsyncTask能够适当地、简单地用于 UI线程。 这个类不需要操作线程(Thread)就可以完成后台操作将结果返回UI。
异步任务的定义是一个在后台线程上运行,其结果是在 UI线程上发布的计算。 异步任务被定义成三种泛型类型: Params,Progress和 Result;和四个步骤: begin ,doInBackground,processProgress 和end。
用法:
在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行。在单线程模型中始终要记住两条法则:
1. 不要阻塞UI线程
2. 确保只在UI线程中访问Android UI工具包
当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
比如说从网上获取一个网页,在一个TextView中将其源代码显示出来,这种涉及到网络操作的程序一般都是需要开一个线程完成网络访问,但是在获得页面源码后,是不能直接在网络操作线程中调用TextView.setText()的.因为其他线程中是不能直接访问主UI线程成员 。
android提供了几种在其他线程中访问UI线程的方法。
Activity.runOnUiThread( Runnable )
View.post( Runnable )
View.postDelayed( Runnable, long )
Hanlder
这些类或方法同样会使你的代码很复杂很难理解。然而当你需要实现一些很复杂的操作并需要频繁地更新UI时这会变得更糟糕。
为了解决这个问题,Android 1.5提供了一个工具类:AsyncTask,它使创建需要与用户界面交互的长时间运行的任务变得更简单。相对来说AsyncTask更轻量级一些,适用于简单的异步处理,不需要借助线程和Handler即可实现。
AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。
Params 启动任务执行的输入参数,比如HTTP请求的URL。
Progress 后台任务执行的百分比。
Result 后台执行任务最终返回的结果,比如String。
AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,这些方法不应该由应用程序调用,开发者需要做的就是实现这些方法。
1) 子类化AsyncTask
2) 实现AsyncTask中定义的下面一个或几个方法
onPreExecute(), 该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。
doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台计算工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.
为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI thread中创建
2) execute方法必须在UI thread中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法
4) 该task只能被执行一次,否则多次调用时将会出现异常
doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。
案例:阅读 http://www.cnblogs.com/dawei/archive/2011/04/18/2019903.html
实际应用
我的方法:
if (!(myTask != null && myTask.getStatus()==AsyncTask.Status.RUNNING)) {
myTask = new PageTask();
myTask.execute(itemMap.get(viewHolder.position),viewHolder);
Log.w("测试", "新线程");
}else if(myTask != null && myTask.getStatus()!=AsyncTask.Status.RUNNING){
myTask.cancel(true);
myTask=null;
myTask = new PageTask();
myTask.execute(itemMap.get(viewHolder.position),viewHolder);
Log.w("测试", "关闭旧线程,开启新线程");
}else {
Log.w("测试", "线程正在运行");
}
点击关闭线程
progressDialog.setButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
myTask.cancel(true);
myTask=null;
}
});
线程断点下载的全部代码
/**
* 线程 下载
*
*/
private class PageTask extends AsyncTask<Object, Integer, String> {
private CityListItem mitem;
private ViewHolder mViewHolder;
private static final int GET_PACK_INFO = 0;// 最新包信息
private static final int DOWNLOAD_FINISH = 1;// 下载完成
private static final int UNPACK_FINISH = 2;// 解压完成
private static final int UPDATE_FINISH = 3;// 更新完成
private static final int UNPACK_ERROR = 4;// 解压有误
private static final int DELETE_TEM_DIR = 5;// 删除零时目录
private static final int ALL_SUCCESS = 6;// 跟新成功
private static final int NO_PACK_INFO = 7;// 无包信息
private static final int UPDATE_BAR = 8;// 更新进度
@Override
protected String doInBackground(Object... params) {
String website;
try {
mitem=(CityListItem)params[0];
mViewHolder=(ViewHolder)params[1];
// 获取包信息....
publishProgress(GET_PACK_INFO);
String packName = PackDataApi.getPack(mitem.city.getId(),
LeziyouConstant.PACK_TYPE_3);
if (packName.equals("")) {
publishProgress(NO_PACK_INFO);
} else {
publishProgress(DOWNLOAD_FINISH);
}
// 下载包...
website = CityDownloadActivity.this.getResources().getString(R.string.webSite)
+ File.separator + "api" + File.separator + packName;
Log.w("Url", website);
Long nPos = 0l;
long localSize = 0;
File file = new File(mitem.packPath);
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
if (!file.exists()) {
file.createNewFile();
} else {
localSize = file.length();
}
int totalSize = FileUtil.getRemoteFileSize(website);
if (localSize < totalSize && localSize != 0) {
Log.w("downLoad", "文件續傳");
nPos = localSize;
}
URL url = new URL(website);
HttpURLConnection httpConnection = (HttpURLConnection) url
.openConnection();
// 设置User-Agent
httpConnection.setRequestProperty("User-Agent", "NetFox");
// 设置断点续传的开始位置
httpConnection.setRequestProperty("RANGE", "bytes=" + nPos + "-");
// 获得输入流
InputStream input = httpConnection.getInputStream();
RandomAccessFile oSavedFile = new RandomAccessFile(mitem.packPath,"rw");
// 定位文件指针到nPos位置
oSavedFile.seek(nPos);
byte[] b = new byte[1024];
int nRead;
int con = (int) localSize;
// 从输入流中读入字节流,然后写到文件中
int i = 0;
int temp = 0;
while ((nRead = input.read(b, 0, 1024)) > 0
&& AppCache.get("isStop") == null) {
if(isCancelled()) return null;// Task被取消了,马上退出循环
(oSavedFile).write(b, 0, nRead);
con += nRead;
i++;
if (i % 10 == 0) {
temp = (con * 100) / totalSize + 1;
if(temp%10==0){
Log.w("测试 temp", temp + "");
}
publishProgress(UPDATE_BAR,(int)temp);
}
}
input.close();
oSavedFile.close();
if (AppCache.get("isStop") != null
&& AppCache.get("isStop").equals("true")) {
Log.w("isStop", "true");
AppCache.remove("isStop");
}
publishProgress(UNPACK_FINISH);
// 解压
if (PackDataApi.unPack(mitem.packPath)) {
// 安装数据
publishProgress(UPDATE_FINISH);
PackDataApi
.updateData(LeziyouConstant.PACK_TYPE_3,
mitem.packPath.substring(0, mitem.packPath
.lastIndexOf(".")), mitem.city
.getId());
publishProgress(DELETE_TEM_DIR);
PackDataApi.delTemDir(mitem.packPath);
publishProgress(ALL_SUCCESS);
} else {
publishProgress(GET_PACK_INFO);
PackDataApi.delTemDir(mitem.packPath);
}
return "success";
} catch (Exception e) {
e.printStackTrace();
if(null!=mitem.packPath){
PackDataApi.delTemDir(mitem.packPath);
}
return null;
}
}
@Override
protected void onCancelled() {
super.onCancelled();
mitem.tvCityName=mitem.city.getName() + "[下载未完成]";
mitem.btDownload="继 续";
mViewHolder.btDownload.setClickable(true);
AppCache.put("isStop", "true");
if(mitem.isFlag==true){//下载完成后解压安装中,则删除包重置
mitem.tvCityName=mitem.city.getName();
mitem.btDownload="下 载";
}
mViewHolder.updataview(mitem);
}
@Override
protected void onPostExecute(String result) {
if(null!=result){
mitem.updateDownload("更 新", "[已更新]");
progressDialog.setMessage("[已更新]");
mViewHolder.btDownload.setClickable(true);
mitem.tvCityName=mitem.tvCityName;
mitem.btDownload=mitem.btDownload;
}
mViewHolder.updataview(mitem);
progressDialog.dismiss();
}
@Override
protected void onPreExecute() {
// 任务启动,可以在这里显示一个对话框,这里简单处理
progressDialog.show();
}
@Override
protected void onProgressUpdate(Integer... values) {
if(isCancelled()) return;// Task被取消了,不再继续执行后面的代码
int i=values[0];
switch (i) {
case GET_PACK_INFO:// 最新包信息
mViewHolder.btDownload.setClickable(false);
progressDialog.setMessage("[请求中...]");
mitem.updateDownload("", "[请求中...]");
break;
case DOWNLOAD_FINISH:// 下载完成
progressDialog.setMessage("[正在下载...]");
mitem.updateDownload("", "[正在下载...]");
break;
case UNPACK_FINISH:// 解压完成
mitem.updateDownload("", "[解压中...]");
progressDialog.setMessage("[解压中...]");
break;
case UPDATE_FINISH:// 更新完成
progressDialog.setMessage("[更新中...]");
mitem.updateDownload("", "[更新中...]");
break;
case UNPACK_ERROR:// 解压有误
progressDialog.setMessage("[解压有误...]");
mitem.updateDownload("", "[解压有误...]");
break;
case DELETE_TEM_DIR:// 删除零时目录
mitem.updateDownload("", "[删除临时目录...]");
progressDialog.setMessage("[删除临时目录...]");
break;
case NO_PACK_INFO:// 无包信息
mitem.updateDownload("", "[暂无]");
mViewHolder.btDownload.setClickable(false);
break;
case ALL_SUCCESS:// 跟新成功!
mitem.updateDownload("更 新", "[已更新]");
progressDialog.setMessage("[已更新]");
progressDialog.dismiss();
mViewHolder.btDownload.setClickable(true);
break;
case UPDATE_BAR:// 更新进度
progressDialog.setProgress(values[1]);
break;
default:
break;
}
mViewHolder.updataview(mitem);
}
}