简介:
AsyncTask是android提供的一个处理异步任务的框架,相当于Handler+Thread。相比而言,AsyncTask的优点是封装良好,代码简洁。
使用AsyncTask可以使你在后台执行耗时任务(doInBackground)并将结果反馈给UI线程(onPostExecute),方便UI线程更新界面,而不会阻塞UI线程。
文档中说AsyncTask只适合执行短时任务,如果你希望让线程长期运行在后台应该使用java.util.concurent并发包中的类,比如Executor,ThreadPoolExecutor和FutureTask。
---------------------------------------------------------------------------------------------------------------
API:
AsyncTask是个抽象类,如果你想使用的话必须显式继承它或者使用匿名内部类的方式。文档中将AsyncTask总结为3个泛型参数(Params,Progress,Result)和4个方法(doInBackground,onPreExecute,omPostExecute,onProgressUpdate).下面分别介绍:
类定义:
public abstract class AsyncTask<Params, Progress, Result>
泛型参数:
Params:执行后台任务所需的参数。比如如果你是网络操作的话,maybe需要传入一个uri
Progress:后台任务执行的进度。比如下载进度,通常是一个Integer,这个参数会被
onProgressUpdate调用,然后去更新UI,比如ProgressBar或者progressDialog。
Result:后台任务执行所返回的结果。比如你想下载一张图片,那可以将Result指定为Bitmap
如果你的AsyncTask不需要某个参数,可以直接指定为Void.
方法简介:
void onPreExecute():在后台任务执行之前会被调用,这个方法是由UI线程调用的,可以用来操作UI,比如你在这个方法里可以设置ProgressBar的可见性。
Result doInBackground(Params... params):这个方法是AsyncTask类中唯一的一个抽象方法,开发者必须复写此方法。从名字上也可看出,这个方法用来执行后台耗时任务,工作在后台线程之上。onPreExecute执行完之后便会执行这个方法。这个方法中的参数是由主线程中调用AsyncTask类的execute方法时传进来的,方法返回的Result会被传递给onPostExecute,用来更新UI。另外这个方法中可以根据执行进度调用publishProgress方法将进度传递给onProgressUpdate方法,然后onProgressUpdate方法也会更新UI(通常是ProgressBar的进度)。
void onProgressUpdate(Progress... values):当你在doInbackground方法中调了publishProgress时,此方法会被调用。这个方法也是工作在UI线程上。通常用这个方法更新progressBar的进度以给用户一个友好提示。
void onPostExecute(Result result):后台任务执行完毕会调用此方法,参数即doInBackground方法返回的那个。这个方法用于更新UI。
除了上面4个方法,还有两个方法常用:
void onCancelled(Result result):这个方法是当用户取消了操作所执行。
final void publishProgress(Progress... values):由doInBackground方法调用,及时发布后台任务的执行进度。不可以复写。
使用AsyncTask需要注意的问题:
- Task的实例必须在UI 线程中创建;
- execute方法必须在UI 线程中调用;
- 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
- 该task只能被执行一次,多次调用execute时将会出现异常;
- 不要在doInBackground方法中更新UI。
这里特别需要注意的就是第四点,异步任务只能调用一次,否则会抛异常,看源码就一目了然了:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); } } ... ...所以你希望多次调用的话,只能new多个AsyncTask了,像这样:
new AsyncTask(){}.execute(..);
使用步骤:
1.继承AsyncTask类,在doInbackground方法中写好逻辑。
2.调用execute方法。
像这样:
new AsyncTask<Void, Void, Void>() { protected Void doInBackground(Void... params) { //TODO handle task return null; } @Override protected void onPostExecute(Void result) { //TODO update UI } }.execute(null);
以下载网络图片为例:
布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ImageView android:id="@+id/iv_show" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1000" /> <Button android:id="@+id/but_down" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="下载" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <ProgressBar android:id="@+id/pb" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" android:layout_gravity="center" /> <TextView android:id="@+id/tv_progress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:background="#fff" android:visibility="gone" android:text="下载进度:" android:textColor="#000" /> </LinearLayout> </FrameLayout>activity:
package com.example.asynctaskdemo4; import java.io.ByteArrayOutputStream; import java.io.InputStream; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private static final String PATH = "http://10.46.191.198:8080/demo.bmp"; private Button but_down = null; private ImageView iv_show = null; private TextView tv_progress = null; private ProgressBar pb = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); but_down = (Button) findViewById(R.id.but_down); iv_show = (ImageView) findViewById(R.id.iv_show); tv_progress = (TextView) findViewById(R.id.tv_progress); pb = (ProgressBar) findViewById(R.id.pb); but_down.setOnClickListener(this); } @Override public void onClick(View v) { if (R.id.but_down == v.getId()) { new DownloadImageTask().execute(PATH); } } private class DownloadImageTask extends AsyncTask<String, Integer, Bitmap> { @Override protected void onPostExecute(Bitmap result) { if (result != null) { tv_progress.setVisibility(View.GONE); pb.setVisibility(View.GONE); iv_show.setImageBitmap(result); } else { tv_progress.setVisibility(View.GONE); pb.setVisibility(View.GONE); Toast.makeText(MainActivity.this,"下载失败",0).show(); } } @Override protected Bitmap doInBackground(String... params) { String path = params[0]; HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(path); try { HttpResponse resp = client.execute(get); if(resp.getStatusLine().getStatusCode() == 200) { HttpEntity entity = resp.getEntity(); if(entity == null) { return null; } long total_length = entity.getContentLength();//获取文件总长 InputStream is = entity.getContent(); ByteArrayOutputStream bous = new ByteArrayOutputStream(); int len = 0; byte[] buf = new byte[1024]; int current_len = 0; int progress = 0;//当前下载进度 while((len = is.read(buf))!= -1) { current_len+=len; bous.write(buf, 0, len); //注意progress的写法哦 progress = (int) ((current_len/(float)total_length)*100); this.publishProgress(progress); } is.close(); byte[] data = bous.toByteArray(); Options opts = new Options(); opts.inSampleSize = 2;//简单起见直接指定缩放比例 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts); return bitmap; } } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onProgressUpdate(Integer... values) { tv_progress.setText("下载进度:"+values[0]); } @Override protected void onPreExecute() { tv_progress.setVisibility(View.VISIBLE); pb.setVisibility(View.VISIBLE); } } }显示效果: