在之前的博文中,我们使用 Handler 在子线程当中更新 UI,但是 Handler 机制不仅庞大,又需要处理它和线程之间的关系,这样不仅代码量庞大,也会容易出错。
Android 为我们提供了 AsyncTask 来帮助我们处理工作线程和主线程之间的关系,它在内部为我们处理了 Thread 和 Handler 之间的关系,使得我们不需要再关注 Thread 和 Handler,只需要关注我们的业务逻辑即可。
按照官方文档来说,AsyncTask 应该用于较短时间的操作(最多几秒钟),如果是长时间的线程运行,还是使用线程池等等。
AsyncTask 通常由 3 个参数 4 个回调方法构成:
3 个参数:
4 个回调方法:
publishProgress(Progress...)
方法来更新任务进度,该方法最终会调用 onProgressUpdate 方法。publishProgress(Progress...)
方法之后会调用该方法,该方法运行在 UI 线程当中,可以用于显示任务进度或者提示信息。例如我们要实现一个功能,点击按钮,下载一张图片,下载完成后将图片设置给 ImageView,在下载的同时实时更新 Progress 的进度。
3 个参数,4 个回调该怎么设置呢?
所以代码大致可以这样写:
public class MainActivity extends Activity {
private ProgressBar progress;
private Button button;
private ImageView image;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progress = findViewById(R.id.progress);
button = findViewById(R.id.button);
image = findViewById(R.id.image);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MyAsyncTask task = new MyAsyncTask();
task.execute("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1502073520254&di=425cf90affda434dbd79ebccf0e773a0&imgtype=0&src=http%3A%2F%2Fn.sinaimg.cn%2Fgames%2Ftransform%2F20160201%2F9B6b-fxnzanh0502003.jpg");
}
});
}
class MyAsyncTask extends AsyncTask<String, Float, Bitmap> {
Bitmap bitmap = null;
@Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(MainActivity.this, "开始下载", Toast.LENGTH_SHORT).show();
}
@Override
protected Bitmap doInBackground(String... params) {
try {
URL url = new URL(params[0]);
URLConnection connection = url.openConnection();
InputStream is = connection.getInputStream();
FileOutputStream fos = openFileOutput("sex.jpg", Context.MODE_PRIVATE);
int length = connection.getContentLength();
int len = 0;
byte[] buf = new byte[1024];
float downloadSize = 0;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
fos.flush();
downloadSize += len;
publishProgress((downloadSize / length) * 100);
Log.d("TTT", "" + downloadSize / length);
}
is.close();
fos.close();
bitmap = BitmapFactory.decodeFile(getApplicationContext().getFilesDir() + "/sex.jpg");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
image.setImageBitmap(bitmap);
}
@Override
protected void onProgressUpdate(Float... values) {
super.onProgressUpdate(values);
progress.setProgress(Math.round(values[0]));
}
}
}
任务时候都可以调用 AsyncTask 的 cancel()
方法来取消任务,在调用了该方法之后,并不会停止后台线程,也就是说,doInBackground 方法还会继续执行,只是在执行完之后,不会调用 pnPostExecute 方法,而是会调用 onCancelled(Result result)
,不过我们可以在 doInBackground 方法当中调用 isCancelled()
判断是否已经取消任务。
最后附上一个稍微全一些的例子:
public class MainActivity extends Activity {
private ProgressBar progress;
private Button start, cancel, stop;
private MyAsyncTask myAsyncTask;
private Object asyncObject = new Object();
private boolean isWait = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progress = findViewById(R.id.progress);
start = findViewById(R.id.start);
cancel = findViewById(R.id.cancel);
stop = findViewById(R.id.stop);
//点击按钮,开始任务
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myAsyncTask = new MyAsyncTask();
myAsyncTask.execute();
}
});
//点击按钮,取消任务
cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myAsyncTask.cancel(true);
}
});
//点击按钮,休眠工作线程,再点击,唤醒...
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
isWait = !isWait;
if (!isWait) {
synchronized (asyncObject) {
asyncObject.notify();
}
}
}
});
}
class MyAsyncTask extends AsyncTask<Void, Integer, Void> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.d("TTT", "任务开始");//任务开始
}
@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 20; i++) {
if (!isCancelled()) { //判断任务是否取消
synchronized (asyncObject) {
try {
if (isWait) { //判断线程是否需要进入wait
asyncObject.wait();
}
publishProgress(i);//更新进度
try {
Thread.currentThread().sleep(500);//休眠500毫秒,模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
break;
}
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.d("TTT", "进度:" + values[0]);//更新进度
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Log.d("TTT", "任务完成");//任务完成
}
@Override
protected void onCancelled(Void aVoid) {
super.onCancelled(aVoid);
Log.d("TTT", "任务取消");//任务取消
}
}
}