Android中通过AsyncTask类来制作炫酷进度条的实例教程
AsyncTask(APIlevel3,所以几乎所有目前在市面上流通的Android版本皆可使用)
是除Thread外的另一种选择,Android团队鼓励主执行绪(UIthread)专注于操作&画面的流畅呈现,
其余工作(如网络资料传输、档案/磁碟/资料存取)最好都在背景执行;
Thread通常要搭配Handler使用,而AsyncTask用意在简化背景执行thread程序码的撰写。
如果您预期要执行的工作能在几秒内完成,就可以选择使用AsyncTask,若执行的时间很长,
Android则强烈建议采用Executor,ThreadPoolExecutorandFutureTask。
要使用AsyncTask,必定要建立一个继承自AsyncTask的子类别,并传入3项资料:
- Params--要执行 doInBackground()时传入的参数,数量可以不止一个
 - Progress-- doInBackground()执行过程中回传给UIthread的资料,数量可以不止一个
 - Rsesult--传回执行结果
 
若您没有参数要传入,则填入Void(注意V为大写)。
AsyncTask的运作有4个阶段:
- onPreExecute--AsyncTask执行前的准备工作,例如画面上显示进度表,
 - doInBackground--实际要执行的程序码就是写在这里,
 - onProgressUpdate--用来显示目前的进度,
 - onPostExecute--执行完的结果- Result会传入这里。
 
除了doInBackground,其他3个method都是在UIthread呼叫
炫酷进度条实例
我们以一个实例来说明,“点击按钮开始下载QQAndroid安装包,然后显示一个对话框来反馈下载进度”。我们先初始化一个对话框,由于要显示进度,我们用Github上面一个能够显示百分比的进度条NumberProgressbar,启动任务的按钮我们使用circlebutton,一个有酷炫动画的按钮,Github上面有很多非常好的开源项目,当然炫酷的控件是其中一部分了,后面有机会,会去学习一些比较流行的控件它们的实现原理,今天就暂且拿来主义了~~。
1.先初始化进度条提示对话框。
builder=newAlertDialog.Builder( MainActivity.this); LayoutInflaterinflater=LayoutInflater.from(MainActivity.this); mDialogView=inflater.inflate(R.layout.progress_dialog_layout,null); mNumberProgressBar=(NumberProgressBar)mDialogView.findViewById(R.id.number_progress_bar); builder.setView(mDialogView); mDialog=builder.create();
2.设置按钮点击事件。
findViewById(R.id.circle_btn).setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
dismissDialog();
mNumberProgressBar.setProgress(0);
myTask=newMyAsyncTask();
myTask.execute(qqDownloadUrl);
}
});
3.DownloadAsyncTask实现,有点长。
privateclassDownloadAsyncTaskextendsAsyncTask<String,Integer,String>{
@Override
protectedvoidonPreExecute(){
super.onPreExecute();
mDialog.show();
}
@Override
protectedvoidonPostExecute(StringaVoid){
super.onPostExecute(aVoid);
dismissDialog();
}
@Override
protectedvoidonProgressUpdate(Integer...values){
super.onProgressUpdate(values);
mNumberProgressBar.setProgress(values[0]);
}
@Override
protectedvoidonCancelled(StringaVoid){
super.onCancelled(aVoid);
dismissDialog();
}
@Override
protectedvoidonCancelled(){
super.onCancelled();
dismissDialog();
}
@Override
protectedStringdoInBackground(String...params){
StringurlStr=params[0];
FileOutputStreamoutput=null;
try{
URLurl=newURL(urlStr);
HttpURLConnectionconnection=(HttpURLConnection)url.openConnection();
StringqqApkFile="qqApkFile";
Filefile=newFile(Environment.getExternalStorageDirectory()+"/"+qqApkFile);
if(file.exists()){
file.delete();
}
file.createNewFile();
InputStreaminput=connection.getInputStream();
output=newFileOutputStream(file);
inttotal=connection.getContentLength();
if(total<=0){
returnnull;
}
intplus=0;
inttotalRead=0;
byte[]buffer=newbyte[4*1024];
while((plus=input.read(buffer))!=-1){
output.write(buffer);
totalRead+=plus;
publishProgress(totalRead*100/total);
if(isCancelled()){
break;
}
}
output.flush();
}catch(MalformedURLExceptione){
e.printStackTrace();
if(output!=null){
try{
output.close();
}catch(IOExceptione2){
e2.printStackTrace();
}
}
}catch(IOExceptione){
e.printStackTrace();
if(output!=null){
try{
output.close();
}catch(IOExceptione2){
e2.printStackTrace();
}
}
}finally{
if(output!=null){
try{
output.close();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
returnnull;
}
}
这样一个简单的下载文件文件就基本实现了,到目前为止谈不上技巧,但是现在我们有一个问题,就是如果我们的Activity正在后台执行一个任务,可能耗时较长,那用户可能会点击返回退出Activity或者退出App,那么后台任务不会立即退出,如果AsyncTask内部有Activity中成员变量的引用,还会造成Activity的回收延时,造成一段时间内的内存泄露,所以我们需要加上下面的第四步处理。
4.onPause中判断应用是否要退出,从而决定是否取消AsyncTask执行。
@Override
protectedvoidonPause(){
super.onPause();
if(myTask!=null&&isFinishing()){
myTask.cancel(false);
}
}
这样我们的异步任务就会在Activity退出时,也随之取消任务执行,顺利被系统销毁回收,第四步很多时候会被遗漏,而且一般也不会有什么致命的问题,但是一旦出问题了,就很难排查,所以遵循编码规范还是有必要的。