异步
什么是异步异步有个兄弟叫同步。同步就像,没刷牙,不能洗脸。异步可以先刷牙或者洗脸,两个没有直接先后顺序。两个同时进行,互不影响。在编程里可以理解为异步操作是多线程操作。
为什么要异步
因为Android如果主线程阻塞5秒就会报ANR(Application Not Responding),所以我们要开一线程进行处理费时的操作,比如获取数据库数据的操作,那就开线程就可以啦,为毛要AsyncTask?因为Android不允许非UI线程对UI控件进行更新。所以我们用到了异步线程
AsyncTask
AsyncTask是android提供的轻量级的异步类(还有一个叫Handler的,在另一blog中介绍)可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。
使用介绍
AsyncTask里面有是抽象类,里面有一抽象方法doInBackground,需要复写。还有一些可选择性重写的方法。说明如下:
执行顺序也是如此。
- onPreExecute—— 线程运行之前执行
- doInBackground——线程后台运行时执行
- onProgressUpdate—— 线程后台运行更新进度
- onPostExecute—— 执行完毕执行
- onCancelled——取消线程运行
-----------------------------------------------------------
一般的,我们复写doInBackground和onPostExecute,如果需要显示进度还需要复写onProgressUpdate。
注意:所有多线程的操作都只能在doInBackground里执行,because:
-------------------------------------------------------------
只有doInBackground里面的代码块才是另开的线程,也说明其他方法里仍运行在主线程。代码如下:
class MAsyncTask extends AsyncTask<String, Integer, Void> {
protected void onPreExecute() {
Log.e("PreExecute", String.valueOf(Thread.currentThread().getName()));
super.onPreExecute();
}
protected Void doInBackground(String... params) {
Log.e("doInBackground", String.valueOf(Thread.currentThread().getName()));
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(i);
}
return null;
}
protected void onProgressUpdate(Integer... values) {
Log.e("onProgressUpdate", String.valueOf(Thread.currentThread().getName()));
pBar.incrementProgressBy(values[0]);
super.onProgressUpdate(values);
}
protected void onPostExecute(Void result) {
Log.e("onPostExecute", String.valueOf(Thread.currentThread().getName()));
super.onPostExecute(result);
}
protected void onCancelled() {
super.onCancelled();
}
}
在UI线程中new AsyncTask对象,执行execute方法,带入可变长的参数(详见博客 java - 可变长参数 ),代码如下:
new MAsyncTask().execute("asd");
注意:
-
execute - 只能在UI线程中调用。
- 不要手动调用AsyncTask里面的所有方法(除onCancelled),进度更新需要在doInBackground里,publishProgress(Params... params)。
- 一个AsyncTask 对象只能execute一次,否则会抛出异常:
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)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}