根据Google自己的说法,AsyncTask只适用于数量不多且短暂的操作,至于原因嘛,可能是因为从Android 3.2开始,AsyncTask又被改成串行的了,这样如果你用AsyncTask执行很多任务,或者某个任务执行时间很长的话,那么后面的任务就没法及时执行了。下面先看它的一个典型用法,然后再具体展开说:
package com.whereru.testcode3;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.ProgressBar;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ImageView mImageView;
private ProgressBar mProgressBar;
private DownloadTask mDownloadTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("MainActivity onCreate");
mImageView = (ImageView) findViewById(R.id.image_view);
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
URL[] urls = null;
try {
urls = new URL[]{
new URL("http://img4.imgtn.bdimg.com/it/u=2317499888,864114656&fm=21&gp=0.jpg"),
new URL("http://img0.imgtn.bdimg.com/it/u=4256573763,278547175&fm=21&gp=0.jpg"),
new URL("http://img2.imgtn.bdimg.com/it/u=546811603,943746655&fm=21&gp=0.jpg"),
new URL("http://img0.imgtn.bdimg.com/it/u=93040804,2971684664&fm=21&gp=0.jpg")
};
} catch (MalformedURLException e) {
e.printStackTrace();
}
mDownloadTask = new DownloadTask(this);
mDownloadTask.execute(urls);
}
@Override
protected void onDestroy() {
super.onDestroy();
mDownloadTask.cancel(false);
System.out.println("MainActivity onDestroy");
}
private static class DownloadTask extends AsyncTask<URL, Integer, List<Bitmap>> {
private WeakReference<MainActivity> mMainActivityWeakReference;
DownloadTask(MainActivity mainActivity) {
mMainActivityWeakReference = new WeakReference<>(mainActivity);
}
@Override
protected List<Bitmap> doInBackground(URL... urls) {
//工作线程,负责下载图片,并转化成Bitmap
HttpURLConnection httpURLConnection = null;
List<Bitmap> bitmapList = new ArrayList<>();
for (int i = 0; i < urls.length; i++) {
System.out.println("正在下载图片:" + (i + 1));
try {
httpURLConnection = (HttpURLConnection)
urls[i].openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException(httpURLConnection.getResponseMessage() + ":with" +
urls[i]);
}
bitmapList.add(BitmapFactory.decodeStream(inputStream));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
if (isCancelled()) {
break;
}
publishProgress((int) (((float) (i + 1) / urls.length) * 100));
}
return bitmapList;
}
@Override
protected void onProgressUpdate(Integer... progress) {
System.out.println("更新进度条");
if (mMainActivityWeakReference.get() != null) {
mMainActivityWeakReference.get().mProgressBar.setProgress(progress[0]);//更新进度条
}
}
@Override
protected void onPostExecute(final List<Bitmap> bitmapList) {
System.out.println("图片下载完成,开始显示图片");
//图片下载完成后,在UI线程中每隔两秒显示一张图片
for (int i = 0; i < bitmapList.size(); i++) {
final int finalI = i;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (mMainActivityWeakReference.get() != null) {
mMainActivityWeakReference.get().mImageView
.setImageBitmap(bitmapList.get(finalI));
}
}
}, 2000 * i);
if (isCancelled()) {
break;
}
}
}
}
}
布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ProgressBar
android:id="@+id/progress_bar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/image_view"
android:layout_width="300dp"
android:layout_height="300dp"/>
</LinearLayout>
上面代码实现的功能就是从网上下载了4张图片,然后有个进度条可以显示下载进度,下载完成后,每隔两秒钟显示一张图片。
下面说下一些注意问题。
0.
如果你觉得Activity被销毁后就不需要相应AsyncTask接着执行任务了,记得在onDestroy中执行cancel方法。
1.
不管在你下载图片还是显示图片的for循环中记得用下:
if (isCancelled()) {
break;
}
这样可以确保在你取消相应任务的时候,可以及时停止接着做无用功。
2.
使用静态内部类和弱引用避免可能发生的内存泄露。(其实我觉得吧,其实如果内存不是很紧张,问题也不是很大,AsyncTask执行完了,自然Activity也就可以被回收了,而AsyncTask本来就不是用来执行长时间任务的,正常使用也不会长时间占着内存,个人看法。。。)
3.
考虑个问题,我们跳到了另一个Acyivity,然后我们并没有取消原来Activity的AsyncTask,而原来的Activity又被销毁了,会怎么样?
如果内存泄露的问题没解决,那程序肯定不会奔溃。那么采用了上面的方法解决了内存泄露,程序就一定会奔溃?其实也不一定,主要看那个被销毁的Activity是不是被GC回收了。不过为了安全起见,我们上面都做了WeakReference.get() != null的判断。
相关阅读:
Android多线程任务优化1:探讨AsyncTask的缺陷