AsyncTask是一种轻量级的异步任务类,不需要借助线程Handler就可以实现,它是在线程池中执行任务,然后把执行的进度和返回结果传递给主线程,在主线程中更新UI
AsyncTask是一个抽象类,定义了3个泛型参数:
- Param:启动任务时需要传入的参数类型
- Progress:后台任务完成进度的参数类型
- Result:任务执行完毕后返回的结果类型
使用AsyncTask的方法如下:
1、定义AsyncTask的子类,指定3个泛型参数类型,如果某个泛型参数不需要指定类型,可以指定为Void
2、重写AsyncTask的方法:
- doPreExecute():在执行后台任务前调用,通常用于一些准备工作,如显示一个进度条
- doInBackground():后台线程将要执行的任务,在此方法中可以调用publishProgress(Progress… values)方法更新进度
- onProgressUpdate(Progress… values):调用publicProgress()方法后会触发该方法
- onPostExecute():当doInBackground()方法完成后会调用该方法,并将doInBackground()方法的返回值传给该方法
3、调用AsyncTask的execute()方法启动任务
下面使用AsyncTask加载一张网络图片
页面布局有一个Button和一个ImageView,点击Button后开始加载图片,用一个进度条显示进度,加载完成后显示在ImageView中
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.testasynctask.MainActivity" >
<Button
android:id="@+id/loadPicture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="加载图片" />
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends ActionBarActivity {
Button loadPicture;
ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadPicture = (Button)findViewById(R.id.loadPicture);
imageView = (ImageView)findViewById(R.id.image);
loadPicture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
LoadTask loadTask = new LoadTask(MainActivity.this);
loadTask.execute("http://pic.qiantucdn.com/58pic/12/57/33/90y58PICcWt.jpg!/fw/780/watermark/url/L3dhdGVybWFyay12MS4zLnBuZw==/align/center");
}
});
}
class LoadTask extends AsyncTask<String, Integer, Bitmap> {
Context context;
ProgressDialog dialog;
long fileSize; //下载的文件大小
public LoadTask(Context context) {
this.context = context;
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
dialog = new ProgressDialog(context);
dialog.setTitle("任务执行中");
dialog.setMessage("正在加载图片...");
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setMax(100);
dialog.setIndeterminate(false);
dialog.show();
}
@Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
try {
URL url = new URL(params[0]);
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
fileSize = connection.getContentLength();
File file = new File("sdcard/image.png");
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
randomAccessFile.setLength(fileSize);
InputStream inputStream = connection.getInputStream();
int readSum = 0;
int hasRead;
byte[] bytes = new byte[1024];
while((hasRead = inputStream.read(bytes)) != -1) {
randomAccessFile.write(bytes, 0, hasRead);
readSum += hasRead;
publishProgress((int)(readSum / fileSize));
}
randomAccessFile.close();
Bitmap bitmap = BitmapFactory.decodeFile("sdcard/image.png");
return bitmap;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
dialog.setProgress(values[0]);
}
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
dialog.dismiss();
imageView.setImageBitmap(result);
}
}
}
点击按钮后开始启动AsyncTask开始下载图片,在开始前先显示了一个下载进度对话框,下载后,先将图片保存在手机存储中,下载完成后将图片作为Bitmap返回,在onPostExecute方法中关闭进度框,然后显示图片
运行程序
加载了一张Batman的海报
使用AsyncTask时有几点需要注意:
1、必须在UI线程中创建AsyncTask
2、必须在UI线程中调用execute()方法
3、不可以直接调用doInBackground()、onPreExecute()、onProgressUpdate()、onPostExecute()方法
4、每个AsyncTask只能执行一次
另外一点,从Android3.0开始,AsyncTask采用一个线程来串行执行任务,可以通过AsyncTask的executeOnExecutor()方法来并行执行任务
新建LoadTask
class LoadTask extends AsyncTask<Void, Void, Void> {
String taskName;
public LoadTask(String name) {
taskName = name;
}
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.i(TAG, "Task " + taskName + " executed");
return null;
}
}
在doInBackground里等待了3秒,然后打印了一句log,在Activity里新建3个Task实例并启动任务
loadPicture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
LoadTask task1 = new LoadTask("Task1");
LoadTask task2 = new LoadTask("Task2");
LoadTask task3 = new LoadTask("Task3");
task1.execute();
task2.execute();
task3.execute();
}
});
运行程序,点击按钮开始任务
每个任务执行耗时3秒,3个任务是依次执行的
使用executeOnExecutor()方法来执行任务
loadPicture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
LoadTask task1 = new LoadTask("Task1");
LoadTask task2 = new LoadTask("Task2");
LoadTask task3 = new LoadTask("Task3");
task1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
task2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
task3.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
});
运行结果
3个任务执行时间是相同的,这也证明任务是并行执行的