使用:新建類繼承AsyncTask,實(shí)現(xiàn)其doInBackground方法
protected void onPreExecute()
protected String doInBackground(String... params)
protected void onProgressUpdate(Integer... values)
protected void onCancelled()
protected void onCancelled(String s)
protected void onPostExecute(String s)
或者直接new
AsyncTask<String, Integer, String> asyncTask
= new AsyncTask<String, Integer, String>() {
@Override
protected String doInBackground(String... params) {
return null;
}
};
asyncTask.execute("hii");
在 doInBackground(String... params)
中要更新UI可以調(diào)用 publishProgress(Progress... values)
, publishProgress()
方法本身執(zhí)行在異步線程杰妓,但會(huì)調(diào)用 Handler 發(fā) MESSAGE_POST_PROGRESS
事件拋到主線程,讓 onProgressUpdate(Integer... values)
處理载矿,不要手動(dòng)調(diào)用 onProgressUpdate(Integer... values)
。
為什么只能在UI線程創(chuàng)建烹卒?
因?yàn)锳ndroid老的版本上用于線程間通信的 InternalHandler 創(chuàng)建時(shí)沒有為其指定Looper闷盔,所以它會(huì)默認(rèn)使用當(dāng)前線程的Looper,如果當(dāng)前線程沒有事先調(diào)用過 Looper.prepare()
旅急,就會(huì)報(bào) RuntimeException("Can't create handler inside thread that has not called Looper.prepare()")
異常逢勾,即使調(diào)用過 Looper.prepare()
由于不是主線程,也不能去修改UI藐吮。至少在API 16上是這樣溺拱,后來的版本里面這條被修改了,AsyncTask 在實(shí)例化 InternalHandler 是為其指定主線程谣辞。
public InternalHandler() {
super(Looper.getMainLooper());
}
為什么只能在主線程中調(diào)用 AsyncTask#execute() ?
先看執(zhí)行代碼:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
@MainThread
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;
}
并沒有為 onPreExecute()
方法的執(zhí)行特別指定線程迫摔,所以 onPreExecute()
是執(zhí)行在當(dāng)前線程,如果要在 onPreExecute()
中修改UI的話泥从,AsyncTask#execute()
就要在UI線程中執(zhí)行句占。
為什么一個(gè)AsyncTask實(shí)例只能執(zhí)行一次?
在并發(fā)條件下多次執(zhí)行execute(),會(huì)讓線程內(nèi)的數(shù)據(jù)不安全躯嫉,并沒有加鎖機(jī)制纱烘,而是限制一個(gè)Task只能被執(zhí)行一次。
其他
仿 AsyncTask 做的一個(gè)單線程執(zhí)行工具(從《Android開發(fā)進(jìn)階》這本書上看到的)
可以改單線程為多個(gè)線程:
private static int coreThreadNum = Runtime.getRuntime().availableProcessors();
private final static ExecutorService executor = new ThreadPoolExecutor(
coreThreadNum, coreThreadNum, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());