1. 程式人生 > >Android AsyncTask類

Android AsyncTask類

相關文章
Android AsyncTask類
Android Handler類

1. AsyncTask類

AsyncTask,非同步任務,用於在後臺執行緒執行一個任務,在UI執行緒上修改介面。AsyncTask<Params, Progress, Result>需要確認三個泛型型別,如果型別不被使用,使用Void型別。

  • Params,啟動任務執行的輸入引數
  • Progress,後臺任務執行的百分比
  • Result,後臺執行結果

例如需要下載一個圖片並顯示在ImageView上,指定Params為圖片地址,Progress以數值代替,Result

返回一個Bitmap物件。

private class BitmapAsyncTask extends AsyncTask<String, Integer, Bitmap> {

    @Override
    protected Bitmap doInBackground(String... strings) {
        try {
            URL uri = new URL(url);
            URLConnection connection = uri.openConnection();
            InputStream input = connection.getInputStream();
            int size = connection.getContentLength();

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            byte[] buffer = new byte[1024];
            int length, sum = 0;

            while ((length = input.read(buffer)) != -1) {
                outputStream.write(buffer, 0, length);
                sum += length;
                publishProgress(sum * 100 / size);
            }
            input.close();

            return BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size());
        } catch (IOException e) {
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        mPb.setProgress(values[0]);
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        mIvBitmap.setImageBitmap(bitmap);
    }
}

BitmapAsyncTask繼承AsyncTask類,且至少覆蓋doInBackground方法

  • onPreExecute(),在UI執行緒上呼叫,在執行後臺執行緒前呼叫
  • doInBackground(Params… params),在後臺執行工作執行緒
  • onProgressUpdate(Progress… values),呼叫publishProgress方法修改進度
  • publishProgress(Progress… values),在UI執行緒呼叫該方法改變進度
  • onPostExecute(Result result),工作執行緒執行完畢,在UI執行緒上修改介面

呼叫execute方法下載

new BitmapAsyncTask().execute(url);

效果如下
在這裡插入圖片描述

2. AsyncTask類解析

AsyncTask構造方法,分別定義了mHandlermWorkermFuture

public AsyncTask() {
    this((Looper) null);
}

public AsyncTask(@Nullable Looper callbackLooper) {
    mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
        ? getMainHandler()
        : new Handler(callbackLooper);

    mWorker = new WorkerRunnable<Params, Result>() {
        public Result call() throws Exception {
            mTaskInvoked.set(true);
            Result result = null;
            try {
                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                //noinspection unchecked
                result = doInBackground(mParams);
                Binder.flushPendingCommands();
            } catch (Throwable tr) {
                mCancelled.set(true);
                throw tr;
            } finally {
                postResult(result);
            }
            return result;
        }
    };

    mFuture = new FutureTask<Result>(mWorker) {
        @Override
        protected void done() {
            try {
                postResultIfNotInvoked(get());
            } catch (InterruptedException e) {
                android.util.Log.w(LOG_TAG, e);
            } catch (ExecutionException e) {
                throw new RuntimeException("An error occurred while executing doInBackground()",
                        e.getCause());
            } catch (CancellationException e) {
                postResultIfNotInvoked(null);
            }
        }
    };
}

mHandler是一個Handler類,處理MESSAGE_POST_RESULTMESSAGE_POST_PROGRESS兩個事件,在主執行緒中呼叫AsyncTask的finishonProgressUpdate方法。

private static Handler getMainHandler() {
    synchronized (AsyncTask.class) {
        if (sHandler == null) {
            sHandler = new InternalHandler(Looper.getMainLooper());
        }
        return sHandler;
    }
}

private static class InternalHandler extends Handler {
    public InternalHandler(Looper looper) {
        super(looper);
    }

    @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
    @Override
    public void handleMessage(Message msg) {
        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch (msg.what) {
            case MESSAGE_POST_RESULT:
                // There is only one result
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        }
    }
}

執行AsyncTask的execute方法,會先呼叫onPreExecute方法,配置mWorkermParams屬性,最後呼叫Executorexecute方法,mFuture會呼叫mWorkcall方法和自身的done方法。call方法呼叫doInBackground,而done方法呼叫postResult

public final AsyncTask<Params, Progress, Result> execute(Params... params) {
    return executeOnExecutor(sDefaultExecutor, params);
}

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;
}

private Result postResult(Result result) {
    @SuppressWarnings("unchecked")
    Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
            new AsyncTaskResult<Result>(this, result));
    message.sendToTarget();
    return result;
}

AsyncTask的publishProgress方法,在UI執行緒裡修改進度。

protected final void publishProgress(Progress... values) {
    if (!isCancelled()) {
        getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
                new AsyncTaskResult<Progress>(this, values)).sendToTarget();
    }
}

3. 總結

  • AsyncTask必須在UI執行緒中被呼叫。
  • doInBackground方法會被自動呼叫,並在後臺執行緒中執行。
  • onPreExecuteonPostExecuteonProgressUpdate會在UI執行緒中被呼叫。
  • doInBackground的返回值會傳給onPostExecute