android AsyncTask原理
9336 ワード
AndroidシステムはUIスレッドのリフレッシュを16 ms程度に維持しており、メインスレッドでいくつかの操作を行う場合は、ユーザーが操作中にカートンを感じないように時間を制限する必要があります.では、時間のかかる操作はメインスレッドで行わないほうがいいです.強引に操作するといろいろな問題がある可能性がありますので、サブスレッドで時間のかかる操作を実現し、メインスレッドにUIを更新するように通知する必要があります.前の記事では、スレッドを作成したり、スレッドプールを作成したりして、この機能を実現することができます.jdk 1で.5の時、1つのAsyncTaskのクラスを出して、このクラスは効果的に私達が上述の要求の機能を実現することを助けて、彼は比較的にいくつかの時間の比較的に短い任務に適用して、内部はスレッドの池をカプセル化して、実現の原理はFutureTask+Callable+SerialExecutor(線程の池)です.まずプロセス全体を説明すると、AsyncTaskの構築方法ではFutureオブジェクトとCallableオブジェクトが作成され、executeメソッドではonPreExecute()メソッドとdoInBackgroundメソッドが実行され、doInbackgroundの結果はMessageにカプセル化され、handlerによってスレッド間通信が行われ、このmessageを通過する.whatは、onProgressUpdateまたはfinishメソッドを呼び出す必要があるかどうかを識別します.finishメソッドではonPostExecuteメソッドが呼び出されます.また,publishProgress()メソッドによりonProgressUpdate()メソッドをアクティブに呼び出すことができ,内部でもこのメソッドによりonProgressUpdateを呼び出すようなメッセージを発行することができる.上のコード:
使用するときは簡単です.上記の方法で需要を書き、直接呼び出します.
次に、ソースコードの分析(android 7.0ベース)を開始します.まず、AsyncTaskの構造関数を見てみましょう.
executeメソッドを実行するには、次の手順に従います.
executeOnExecutorメソッドを見てみましょう.
このexecuteがどのように呼び出されるか見てみましょう
以上、mWorkerのcallメソッドを再実行しました.このcallメソッドはサブスレッドで実行されていることがわかります.postResultメソッドを見てみましょう.
最後にこのfinishメソッドを見てみましょう.
その後、handlerのMESSAGEを実行する方法を見てみましょう.POST_PROGRESSブランチができました.
プロセス全体が順調に進みました.最後に、現在実行中のタスクをキャンセルする方法を見てみましょう.
まとめ:アプリケーション全体のすべてのAsyncTaskインスタンスは、同じSerialExecutorを共有します.彼はArrayDueueですべてのRunnableを管理しています.それでは、すべてのタスクは1つのキューの中にあります.彼はexecuteメソッドで、scheduleNextを通じて、1つ1つのキューからヘッダタスクを取り出して実行します.その後に追加されたタスクは、キューの最後に配置されます.全体的に見ると、このSerialExecutorは、機能的には単一のスレッドプールに属しており、多くのタスクを迅速に開始すると、同じ時点で1つのスレッドしか実行されず、残りは待機状態にあります.4.0以前のバージョンでは、ThreadPoolExecutorを直接使用しており、コアスレッド数が5、バススレッド数が128のスレッドプールが使用されていました.現在のAsyncTaskでは、スレッドプールをカスタマイズして、対応する操作を行うことができます.柔軟性が高いです.要するに、AsyncTaskも非同期メッセージ処理メカニズムを使用しており、非常に良いパッケージを作っただけです.
class MyAsyncTask extends AsyncTask {
// Params : , doInBackground
// Progress: onProgressUpdate ,
// Result : doInBackground , onPostExecute
@Override
protected void onPreExecute() {
super.onPreExecute();
//
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// UI
}
@Override
protected Boolean doInBackground(Void... params) {
//
return null;
}
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
// UI UI
}
}
使用するときは簡単です.上記の方法で需要を書き、直接呼び出します.
new MyAsyncTask().execute();// +
次に、ソースコードの分析(android 7.0ベース)を開始します.まず、AsyncTaskの構造関数を見てみましょう.
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
* ui
*/
public AsyncTask() {
// Callable
mWorker = new WorkerRunnable() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
Result result = doInBackground(mParams);
Binder.flushPendingCommands();
return postResult(result);
}
};
// FuntureTask Callable
mFuture = new FutureTask(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);
}
}
};
}
executeメソッドを実行するには、次の手順に従います.
// execute :
//This method must be invoked on the UI thread.
@MainThread
public final AsyncTask execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);//
}
// ,
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
// AsyncTask SerialExecutor
executeOnExecutorメソッドを見てみましょう.
@MainThread
public final AsyncTask 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(); // onPreExecute UI
mWorker.mParams = params;
// exec SerialExecutor
exec.execute(mFuture);// futureTask
return this;
}
このexecuteがどのように呼び出されるか見てみましょう
private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque(); // ArrayDeque,
Runnable mActive;//
// Runnable mFuture
public synchronized void execute(final Runnable r) {
// offer ,
mTasks.offer(new Runnable() {
public void run() {
//
try {
r.run();// mFuture mWorker
// call doInBackground
} finally {
scheduleNext();
}
}
});
// null scheduleNext
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
// mActive,
if ((mActive = mTasks.poll()) != null) {
// ThreadPoolExecute
// ,
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
以上、mWorkerのcallメソッドを再実行しました.このcallメソッドはサブスレッドで実行されていることがわかります.postResultメソッドを見てみましょう.
private Result postResult(Result result) {
// result Message , handler
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();// message
return result;
}
// handler
private static Handler getHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler();
}
return sHandler;
}
}
// Handler
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@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: // publishProgress() message
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
最後にこのfinishメソッドを見てみましょう.
private void finish(Result result) {
if (isCancelled()) {// true
onCancelled(result);
} else {//
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
その後、handlerのMESSAGEを実行する方法を見てみましょう.POST_PROGRESSブランチができました.
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult
プロセス全体が順調に進みました.最後に、現在実行中のタスクをキャンセルする方法を見てみましょう.
execute.cancel(true);//
// , false ,
//
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true);// true, value 1
return mFuture.cancel(mayInterruptIfRunning);// future callable
}
// value 1 finish onCancelled() ,
まとめ:アプリケーション全体のすべてのAsyncTaskインスタンスは、同じSerialExecutorを共有します.彼はArrayDueueですべてのRunnableを管理しています.それでは、すべてのタスクは1つのキューの中にあります.彼はexecuteメソッドで、scheduleNextを通じて、1つ1つのキューからヘッダタスクを取り出して実行します.その後に追加されたタスクは、キューの最後に配置されます.全体的に見ると、このSerialExecutorは、機能的には単一のスレッドプールに属しており、多くのタスクを迅速に開始すると、同じ時点で1つのスレッドしか実行されず、残りは待機状態にあります.4.0以前のバージョンでは、ThreadPoolExecutorを直接使用しており、コアスレッド数が5、バススレッド数が128のスレッドプールが使用されていました.現在のAsyncTaskでは、スレッドプールをカスタマイズして、対応する操作を行うことができます.柔軟性が高いです.要するに、AsyncTaskも非同期メッセージ処理メカニズムを使用しており、非常に良いパッケージを作っただけです.