前言
AsyncTask是Android开发中经常使用的一个轻量级异步类;其作用作用可以用来1.实现多线程(在工作线程中执行耗时任务) 2. 异步通信(工作线程和主线程之前的通信);其本质,单个AsyncTask对象中包含一个Callable+FutureTask任务+主线程handler处理子线程传过来的结果;AsyncTask类中包含两个线程池,用来给任务排序以及处理任务
AsyncTask使用范例
package com.test.weijuncheng.testasynctask;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {
private Button btn;
private ImageView imageView;
private ProgressDialog progressDialog;
private final String IMAGE_PATH = "http://developer.android.com/images/home/kk-hero.jpg";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.button);
imageView = (ImageView)findViewById(R.id.imageView);
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("提示信息");
progressDialog.setMessage("正在下载中,请稍候");
progressDialog.setCancelable(false);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyAsyncTask().execute(IMAGE_PATH);
}
});
}
public class MyAsyncTask extends AsyncTask<String,Integer,byte[]> {
/**
* 定义一个类,让其继承AsyncTask这个类
* Params: String类型,表示传递给异步任务的参数类型是String,通常指定的是URL路径
* Progress: Integer类型,进度条的单位通常都是Integer类型
* Result:byte[]类型,表示我们下载好的图片以字节数组返回
*
*/
@Override
protected void onPreExecute() {
Log.e("weijuncheng","onPreExecute called, current thread id = "+Thread.currentThread().getId());
super.onPreExecute();
progressDialog.show();
}
@Override
protected void onPostExecute(byte[] bytes) {
Log.e("weijuncheng","onPostExecute called, current thread id = "+Thread.currentThread().getId());
super.onPostExecute(bytes);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length); //将doInBackground返回的byte数组转换为bitmap
imageView.setImageBitmap(bitmap);
progressDialog.dismiss();
}
@Override
protected void onProgressUpdate(Integer... values) {
Log.e("weijuncheng","onProgressUpdate called, current thread id = "+Thread.currentThread().getId());
super.onProgressUpdate(values);
progressDialog.setProgress(values[0]);
}
@Override
protected byte[] doInBackground(String... strings) {
Log.e("weijuncheng","doInBackground called, current thread id = "+Thread.currentThread().getId());
HttpClient httpClient = new DefaultHttpClient(); //useLibrary 'org.apache.http.legacy'
//CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(strings[0]);
byte[] image = new byte[]{};
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
InputStream inputStream = null;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
if(httpEntity!=null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
long file_length = httpEntity.getContentLength();; //文件总长度,现在已弃用
//Log.e("weijuncheng","file_length = "+file_length);
long total_length = 0;//每次读取后累加的长度
long length = 0;
byte[] data = new byte[1024];
inputStream = httpEntity.getContent();
while(-1 != (length = inputStream.read(data))){
//Log.e("weijuncheng","length = "+length);
total_length += length;
// 边读边写到ByteArrayOutputStream当中
byteArrayOutputStream.write(data,0, (int) length);
// 得到当前图片下载的进度
int progress = ((int)(total_length/(float)128390) * 100);
// 时刻将当前进度更新给onProgressUpdate方法
publishProgress(progress);
}
image = byteArrayOutputStream.toByteArray();
inputStream.close();
byteArrayOutputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
httpClient.getConnectionManager().shutdown();
}
return image;
}
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
useLibrary 'org.apache.http.legacy'
defaultConfig {
applicationId "com.test.weijuncheng.testasynctask"
minSdkVersion 18
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
也可以取消任务
new MyAsyncTask().cancel(true); //取消正在执行的任务,AsyncTask中的onCancelled方法将会被调用
AsyncTask源码分析
/**
* <p>AsyncTask enables proper and easy use of the UI thread. This class allows you
* to perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.</p>
*
* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the <code>java.util.concurrent</code> package such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
*
* <p>An asynchronous task is defined by a computation that runs on a background thread and
* whose result is published on the UI thread. An asynchronous task is defined by 3 generic
* types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
* and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
* <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using tasks and threads, read the
* <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and
* Threads</a> developer guide.</p>
* </div>
*
* <h2>Usage</h2>
* <p>AsyncTask must be subclassed to be used. The subclass will override at least
* one method ({@link #doInBackground}), and most often will override a
* second one ({@link #onPostExecute}.)</p>
*
* <p>Here is an example of subclassing:</p>
* <pre class="prettyprint">
* private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
* protected Long doInBackground(URL... urls) {
* int count = urls.length;
* long totalSize = 0;
* for (int i = 0; i < count; i++) {
* totalSize += Downloader.downloadFile(urls[i]);
* publishProgress((int) ((i / (float) count) * 100));
* // Escape early if cancel() is called
* if (isCancelled()) break;
* }
* return totalSize;
* }
*
* protected void onProgressUpdate(Integer... progress) {
* setProgressPercent(progress[0]);
* }
*
* protected void onPostExecute(Long result) {
* showDialog("Downloaded " + result + " bytes");
* }
* }
* </pre>
*
* <p>Once created, a task is executed very simply:</p>
* <pre class="prettyprint">
* new DownloadFilesTask().execute(url1, url2, url3);
* </pre>
*
* <h2>AsyncTask's generic types</h2>
* <p>The three types used by an asynchronous task are the following:</p>
* <ol>
* <li><code>Params</code>, the type of the parameters sent to the task upon
* execution.</li>
* <li><code>Progress</code>, the type of the progress units published during
* the background computation.</li>
* <li><code>Result</code>, the type of the result of the background
* computation.</li>
* </ol>
* <p>Not all types are always used by an asynchronous task. To mark a type as unused,
* simply use the type {@link Void}:</p>
* <pre>
* private class MyTask extends AsyncTask<Void, Void, Void> { ... }
* </pre>
*
* <h2>The 4 steps</h2>
* <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
* <ol>
* <li>{@link #onPreExecute()}, invoked on the UI thread before the task
* is executed. This step is normally used to setup the task, for instance by
* showing a progress bar in the user interface.</li>
* <li>{@link #doInBackground}, invoked on the background thread
* immediately after {@link #onPreExecute()} finishes executing. This step is used
* to perform background computation that can take a long time. The parameters
* of the asynchronous task are passed to this step. The result of the computation must
* be returned by this step and will be passed back to the last step. This step
* can also use {@link #publishProgress} to publish one or more units
* of progress. These values are published on the UI thread, in the
* {@link #onProgressUpdate} step.</li>
* <li>{@link #onProgressUpdate}, invoked on the UI thread after a
* call to {@link #publishProgress}. The timing of the execution is
* undefined. This method is used to display any form of progress in the user
* interface while the background computation is still executing. For instance,
* it can be used to animate a progress bar or show logs in a text field.</li>
* <li>{@link #onPostExecute}, invoked on the UI thread after the background
* computation finishes. The result of the background computation is passed to
* this step as a parameter.</li>
* </ol>
*
* <h2>Cancelling a task</h2>
* <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
* this method will cause subsequent calls to {@link #isCancelled()} to return true.
* After invoking this method, {@link #onCancelled(Object)}, instead of
* {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
* returns. To ensure that a task is cancelled as quickly as possible, you should always
* check the return value of {@link #isCancelled()} periodically from
* {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>
*
* <h2>Threading rules</h2>
* <p>There are a few threading rules that must be followed for this class to
* work properly:</p>
* <ul>
* <li>The AsyncTask class must be loaded on the UI thread. This is done
* automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
* <li>The task instance must be created on the UI thread.</li>
* <li>{@link #execute} must be invoked on the UI thread.</li>
* <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
* {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
* <li>The task can be executed only once (an exception will be thrown if
* a second execution is attempted.)</li>
* </ul>
*
* <h2>Memory observability</h2>
* <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following
* operations are safe without explicit synchronizations.</p>
* <ul>
* <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them
* in {@link #doInBackground}.
* <li>Set member fields in {@link #doInBackground}, and refer to them in
* {@link #onProgressUpdate} and {@link #onPostExecute}.
* </ul>
*
* <h2>Order of execution</h2>
* <p>When first introduced, AsyncTasks were executed serially on a single background
* thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operate in parallel. Starting with
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single
* thread to avoid common application errors caused by parallel execution.</p>
* <p>If you truly want parallel execution, you can invoke
* {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with
* {@link #THREAD_POOL_EXECUTOR}.</p>
*/
public abstract class AsyncTask<Params, Progress, Result> {
private static final String LOG_TAG = "AsyncTask";
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //CPU核心数
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); //线程池核心线程数
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; //线程池最大线程数
private static final int KEEP_ALIVE_SECONDS = 30; //线程闲置超时时间
private static final ThreadFactory sThreadFactory = new ThreadFactory() { //线程工厂
private final AtomicInteger mCount = new AtomicInteger(1); //mCount是线程安全的
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128); //一个阻塞的线程安全的队列,底层采用链表实现
/*
add方法在添加元素的时候,若超出了度列的长度会直接抛出异常:
put方法,若向队尾添加元素的时候发现队列已经满了会发生阻塞一直等待空间,以加入元素。
offer方法在添加元素时,如果发现队列已满无法添加的话,会直接返回false
(阻塞队列的含义)阻塞队列是一个在队列基础上又支持了两个附加操作的队列。
2个附加操作:
支持阻塞的插入方法:队列满时,队列会阻塞插入元素的线程,直到队列不满。
支持阻塞的移除方法:队列空时,获取元素的线程会等待队列变为非空
*/
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR; //执行任务的线程池(这个线程池用于执行任务)
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor; //构造一个ThreadPoolExecutor线程池,用到了上面的常量
}
//注意这两个线程池是static的;也就是与类相关,而不是与对象相关,这就是为什么需要使用线程池的原因
/**
* An {@link Executor} that executes tasks one at a time in serial
* order. This serialization is global to a particular process.
*/
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static InternalHandler sHandler;
private final WorkerRunnable<Params, Result> mWorker;
private final FutureTask<Result> mFuture;
private volatile Status mStatus = Status.PENDING;
private final AtomicBoolean mCancelled = new AtomicBoolean();
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
private final Handler mHandler;
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); //SerialExecutor 内部维持了1个双向队列,维护所有AsyncTask添加的队列
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() { //添加当前任务
public void run() {
try {
r.run();
} finally {
scheduleNext(); //添加完当前任务之后,计划执行队列中下一个任务
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive); //取出队头任务开始执行,执行相应任务callable的call函数
}
}
}
/**
* Indicates the current status of the task. Each status will be set only once
* during the lifetime of a task.
*/
public enum Status {
/**
* Indicates that the task has not been executed yet.
*/
PENDING,
/**
* Indicates that the task is running.
*/
RUNNING,
/**
* Indicates that {@link AsyncTask#onPostExecute} has finished.
*/
FINISHED,
}
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper()); //InternalHandler为主线程对应handler
}
return sHandler;
}
}
private Handler getHandler() {
return mHandler;
}
/** @hide */
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
this((Looper) null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() { //Callable队形
public Result call() throws Exception {
mTaskInvoked.set(true); //mTaskInvoked = true,说明任务被执行了,调用了call方法
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; //返回doInBackground的结果(Callable不同于Runnale的地方就在于其有返回结果)
}
};
mFuture = new FutureTask<Result>(mWorker) { //mFuture即是Callable,也是可以得到结果的Future
@Override
protected void done() {
//FutureTask#done * Protected method invoked when this task transitions to state * {@code isDone} (whether normally or via cancellation).
try {
postResultIfNotInvoked(get()); //通过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);
}
}
};
//mWork和mFuture是与AsyncTask对象相关的,线程池是与类相关的;说明一个AysncTask对象对应一个任务
}
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result); //如果task没有被执行,被取消了,也将结果通过postResult;由InternalHandler传递到UI线程
}
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
/**
* Returns the current status of this task.
*
* @return The current status.
*/
public final Status getStatus() {
return mStatus;
}
/**
* Override this method to perform a computation on a background thread. The
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
*
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
* @param params The parameters of the task.
*
* @return A result, defined by the subclass of this task.
*
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
@WorkerThread
protected abstract Result doInBackground(Params... params);
/**
* Runs on the UI thread before {@link #doInBackground}.
*
* @see #onPostExecute
* @see #doInBackground
*/
@MainThread
protected void onPreExecute() {
}
/**
* <p>Runs on the UI thread after {@link #doInBackground}. The
* specified result is the value returned by {@link #doInBackground}.</p>
*
* <p>This method won't be invoked if the task was cancelled.</p>
*
* @param result The result of the operation computed by {@link #doInBackground}.
*
* @see #onPreExecute
* @see #doInBackground
* @see #onCancelled(Object)
*/
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onPostExecute(Result result) {
}
/**
* Runs on the UI thread after {@link #publishProgress} is invoked.
* The specified values are the values passed to {@link #publishProgress}.
*
* @param values The values indicating progress.
*
* @see #publishProgress
* @see #doInBackground
*/
@SuppressWarnings({"UnusedDeclaration"})
@MainThread
protected void onProgressUpdate(Progress... values) {
}
/**
* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
* {@link #doInBackground(Object[])} has finished.</p>
*
* <p>The default implementation simply invokes {@link #onCancelled()} and
* ignores the result. If you write your own implementation, do not call
* <code>super.onCancelled(result)</code>.</p>
*
* @param result The result, if any, computed in
* {@link #doInBackground(Object[])}, can be null
*
* @see #cancel(boolean)
* @see #isCancelled()
*/
@SuppressWarnings({"UnusedParameters"})
@MainThread
protected void onCancelled(Result result) {
onCancelled();
}
/**
* <p>Applications should preferably override {@link #onCancelled(Object)}.
* This method is invoked by the default implementation of
* {@link #onCancelled(Object)}.</p>
*
* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
* {@link #doInBackground(Object[])} has finished.</p>
*
* @see #onCancelled(Object)
* @see #cancel(boolean)
* @see #isCancelled()
*/
@MainThread
protected void onCancelled() {
}
/**
* Returns <tt>true</tt> if this task was cancelled before it completed
* normally. If you are calling {@link #cancel(boolean)} on the task,
* the value returned by this method should be checked periodically from
* {@link #doInBackground(Object[])} to end the task as soon as possible.
*
* @return <tt>true</tt> if task was cancelled before it completed
*
* @see #cancel(boolean)
*/
public final boolean isCancelled() {
return mCancelled.get();
}
/**
* <p>Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, already been cancelled,
* or could not be cancelled for some other reason. If successful,
* and this task has not started when <tt>cancel</tt> is called,
* this task should never run. If the task has already started,
* then the <tt>mayInterruptIfRunning</tt> parameter determines
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.</p>
*
* <p>Calling this method will result in {@link #onCancelled(Object)} being
* invoked on the UI thread after {@link #doInBackground(Object[])}
* returns. Calling this method guarantees that {@link #onPostExecute(Object)}
* is never invoked. After invoking this method, you should check the
* value returned by {@link #isCancelled()} periodically from
* {@link #doInBackground(Object[])} to finish the task as early as
* possible.</p>
*
* @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete.
*
* @return <tt>false</tt> if the task could not be cancelled,
* typically because it has already completed normally;
* <tt>true</tt> otherwise
*
* @see #isCancelled()
* @see #onCancelled(Object)
*/
public final boolean cancel(boolean mayInterruptIfRunning) {
mCancelled.set(true); //调用AsyncTask的cancel取消其中包含的任务的执行
return mFuture.cancel(mayInterruptIfRunning);
}
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return The computed result.
*
* @throws CancellationException If the computation was cancelled.
* @throws ExecutionException If the computation threw an exception.
* @throws InterruptedException If the current thread was interrupted
* while waiting.
*/
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get(); //通过AsyncTask中的mFuture中的get,可以得到子线程的执行结果,并阻塞主进程(住进程等待结果)
}
/**
* Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result.
*
* @param timeout Time to wait before cancelling the operation.
* @param unit The time unit for the timeout.
*
* @return The computed result.
*
* @throws CancellationException If the computation was cancelled.
* @throws ExecutionException If the computation threw an exception.
* @throws InterruptedException If the current thread was interrupted
* while waiting.
* @throws TimeoutException If the wait timed out.
*/
public final Result get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
return mFuture.get(timeout, unit);
}
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>Note: this function schedules the task on a queue for a single background
* thread or pool of threads depending on the platform version. When first
* introduced, AsyncTasks were executed serially on a single background thread.
* Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operate in parallel. Starting
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
* executed on a single thread to avoid common application errors caused
* by parallel execution. If you truly want parallel execution, you can use
* the {@link #executeOnExecutor} version of this method
* with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
* on its use.
*
* <p>This method must be invoked on the UI thread.
*
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
* @see #execute(Runnable)
*/
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params); //初始化完成后,在主线程调用AsyncTask对象的excute;注意,参数不是构造AsyncTask时添加,而是调用excute时添加
}
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
* allow multiple tasks to run in parallel on a pool of threads managed by
* AsyncTask, however you can also use your own {@link Executor} for custom
* behavior.
*
* <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
* a thread pool is generally <em>not</em> what one wants, because the order
* of their operation is not defined. For example, if these tasks are used
* to modify any state in common (such as writing a file due to a button click),
* there are no guarantees on the order of the modifications.
* Without careful work it is possible in rare cases for the newer version
* of the data to be over-written by an older one, leading to obscure data
* loss and stability issues. Such changes are best
* executed in serial; to guarantee such work is serialized regardless of
* platform version you can use this function with {@link #SERIAL_EXECUTOR}.
*
* <p>This method must be invoked on the UI thread.
*
* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
* convenient process-wide thread pool for tasks that are loosely coupled.
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execute(Object[])
*/
@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(); //主线程执行onPreExecute
mWorker.mParams = params; //添加参数到任务中,则mFuture的参数也更新过了
exec.execute(mFuture);
return this;
}
/**
* Convenience version of {@link #execute(Object...)} for use with
* a simple Runnable object. See {@link #execute(Object[])} for more
* information on the order of execution.
*
* @see #execute(Object[])
* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
*/
@MainThread
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
/**
* This method can be invoked from {@link #doInBackground} to
* publish updates on the UI thread while the background computation is
* still running. Each call to this method will trigger the execution of
* {@link #onProgressUpdate} on the UI thread.
*
* {@link #onProgressUpdate} will not be called if the task has been
* canceled.
*
* @param values The progress values to update the UI with.
*
* @see #onProgressUpdate
* @see #doInBackground
*/
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget(); //执行过程中更新UI界面
}
}
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result); //任务是否取消,取消调用onCancelled
} else {
onPostExecute(result); //否则调用onPostExecute,对得到结果进行收尾,如更新UI
}
mStatus = Status.FINISHED;
}
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]); //就是调用AsyncTask的finish方法;任务执行完成或者取消时均有可能调用finish
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData); //就是调用AsyncTask的onProgressUpdate方法
break;
}
}
}
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> { //AsyncTaskResult AsyncTask当前对象的引用,以及当前对象的任务的执行结果的集合
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
}
AsyncTask-step 1初始化
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
mWorker = new WorkerRunnable<Params, Result>() { //Callable队形
public Result call() throws Exception {
mTaskInvoked.set(true); //mTaskInvoked = true,说明任务被执行了,调用了call方法
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; //返回doInBackground的结果(Callable不同于Runnale的地方就在于其有返回结果)
}
};
mFuture = new FutureTask<Result>(mWorker) { //mFuture即是Callable,也是可以得到结果的Future
@Override
protected void done() {
//FutureTask#done * Protected method invoked when this task transitions to state * {@code isDone} (whether normally or via cancellation).
try {
postResultIfNotInvoked(get()); //通过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);
}
}
};
//mWork和mFuture是与AsyncTask对象相关的,线程池是与类相关的;说明一个AysncTask对象对应一个任务
}
构造Callable(mWorker)以及对应的FutureTask(mFuture)
AsyncTask-step 2 excute
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>Note: this function schedules the task on a queue for a single background
* thread or pool of threads depending on the platform version. When first
* introduced, AsyncTasks were executed serially on a single background thread.
* Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operate in parallel. Starting
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
* executed on a single thread to avoid common application errors caused
* by parallel execution. If you truly want parallel execution, you can use
* the {@link #executeOnExecutor} version of this method
* with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
* on its use.
*
* <p>This method must be invoked on the UI thread.
*
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
* @see #execute(Runnable)
*/
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params)
return executeOnExecutor(sDefaultExecutor, params); //初始化完成后,在主线程调用AsyncTask对象的excute;注意,参数不是构造AsyncTask时添加,而是调用excute时添加
}
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
* allow multiple tasks to run in parallel on a pool of threads managed by
* AsyncTask, however you can also use your own {@link Executor} for custom
* behavior.
*
* <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
* a thread pool is generally <em>not</em> what one wants, because the order
* of their operation is not defined. For example, if these tasks are used
* to modify any state in common (such as writing a file due to a button click),
* there are no guarantees on the order of the modifications.
* Without careful work it is possible in rare cases for the newer version
* of the data to be over-written by an older one, leading to obscure data
* loss and stability issues. Such changes are best
* executed in serial; to guarantee such work is serialized regardless of
* platform version you can use this function with {@link #SERIAL_EXECUTOR}.
*
* <p>This method must be invoked on the UI thread.
*
* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
* convenient process-wide thread pool for tasks that are loosely coupled.
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execute(Object[])
*/
@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(); //主线程执行onPreExecute
mWorker.mParams = params; //添加参数到任务中,则mFuture的参数也更新过了
exec.execute(mFuture);
return this;
}
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>(); //SerialExecutor 内部维持了1个双向队列,维护所有AsyncTask添加的队列
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() { //添加当前任务
public void run() {
try {
r.run();
} finally {
scheduleNext(); //添加完当前任务之后,计划执行队列中下一个任务
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive); //取出队头任务开始执行,执行相应任务callable的call函数
}
}
}
最终还是通过THREAD_POOL_EXECUTOR.execute执行mWorker中定义的call函数
mWorker = new WorkerRunnable<Params, Result>() { //Callable队形
public Result call() throws Exception {
mTaskInvoked.set(true); //mTaskInvoked = true,说明任务被执行了,调用了call方法
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; //返回doInBackground的结果(Callable不同于Runnale的地方就在于其有返回结果)
}
};
最终不论任务是执行完成了还是取消了(通过postResultIfNotInvoked),都会调用postResult
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
AsyncTask-step 3 处理结果
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
与主线程Handler通信
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]); //就是调用AsyncTask的finish方法;任务执行完成或者取消时均有可能调用finish
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData); //就是调用AsyncTask的onProgressUpdate方法
break;
}
}
}
调用AsyncTask#finish
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result); //任务是否取消,取消调用onCancelled
} else {
onPostExecute(result); //否则调用onPostExecute,对得到结果进行收尾,如更新UI
}
mStatus = Status.FINISHED;
}
总结
单个AsyncTask本质就是thread+handler
然后AsyncTask类含有两个线程池,一个用来任务排序,一个用来任务执行
优点:封装完善
有很多AsyncTask申请任务时,用了线程池节省系统资源
AsyncTask与IntentService个人理解
相同点:都是封装多线程执行任务
不同点:1.IntentService本质是Service+Handler; AsyncTask本质是Callable(Thread+Handler)+FutureTask
2.IntentService因为本质是Service,应该可以跨进程通信;
AsyncTask可以子线程和主线程之间通信,是双向的;子线程的执行结果可以通知主线程
那么使用场景还是不一样的,IntentService多用于后台的耗时操作,其不会影响主界面的显示功能;而AsyncTask则正相反
拓展
如果我们将线程池shutdown会怎样呢?
public class MainActivity extends AppCompatActivity {
private Button btn;
private Button btn1;
private Button btn2;
private Handler handler;
private ImageView imageView;
private ProgressDialog progressDialog;
private final String IMAGE_PATH = "http://developer.android.com/images/home/kk-hero.jpg";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.button);
btn1 = (Button)findViewById(R.id.button1);
btn2 = (Button)findViewById(R.id.button2);
imageView = (ImageView)findViewById(R.id.imageView);
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
Log.i("weijuncheng","start Shutdown");
((ExecutorService)AsyncTask.THREAD_POOL_EXECUTOR).shutdown();
break;
case 2:
Log.i("weijuncheng","start ShutdownNow");
((ExecutorService)AsyncTask.THREAD_POOL_EXECUTOR).shutdownNow();
break;
default:
break;
}
}
};
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("提示信息");
progressDialog.setMessage("正在下载中,请稍候");
progressDialog.setCancelable(false);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyAsyncTask().execute(IMAGE_PATH);
}
});
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(int i = 0;i<200;i++){
new TestAsyncTask().execute();
}
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.sendMessageAtTime(handler.obtainMessage(1),5000);
}
});
}
package com.test.weijuncheng.testasynctask;
import android.os.AsyncTask;
import android.util.Log;
public class TestAsyncTask extends AsyncTask<Void,Void,Void> {
@Override
protected void onCancelled(Void aVoid) {
Log.e("weijuncheng","--------------------------------->onCancelled called, current thread is = "+Thread.currentThread().getId()+" thread name is = "+Thread.currentThread().getName());
super.onCancelled(aVoid);
}
@Override
protected Void doInBackground(Void... voids) {
try {
Thread.sleep(500); //模拟执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("weijuncheng","--------------------------------->doInBackground called, current thread is = "+Thread.currentThread().getId()+" thread name is = "+Thread.currentThread().getName());
return null;
}
}
log如下
02-21 02:49:04.296 3590 3618 E weijuncheng: --------------------------------->doInBackground called, current thread is = 863 thread name is = AsyncTask #1
02-21 02:49:04.838 3590 3619 E weijuncheng: --------------------------------->doInBackground called, current thread is = 864 thread name is = AsyncTask #2
02-21 02:49:05.381 3590 3620 E weijuncheng: --------------------------------->doInBackground called, current thread is = 865 thread name is = AsyncTask #3
02-21 02:49:05.925 3590 3620 I chatty : uid=10104(com.test.weijuncheng.testasynctask) AsyncTask #3 identical 1 line
02-21 02:49:06.467 3590 3620 E weijuncheng: --------------------------------->doInBackground called, current thread is = 865 thread name is = AsyncTask #3
02-21 02:49:06.989 3590 3620 E weijuncheng: --------------------------------->doInBackground called, current thread is = 865 thread name is = AsyncTask #3
02-21 02:49:07.532 3590 3620 E weijuncheng: --------------------------------->doInBackground called, current thread is = 865 thread name is = AsyncTask #3
02-21 02:49:08.579 3590 3620 I chatty : uid=10104(com.test.weijuncheng.testasynctask) AsyncTask #3 identical 2 lines
02-21 02:49:09.089 3590 3620 E weijuncheng: --------------------------------->doInBackground called, current thread is = 865 thread name is = AsyncTask #3
02-21 02:49:09.469 3590 3590 I weijuncheng: start Shutdown
02-21 02:49:09.627 3590 3620 E weijuncheng: --------------------------------->doInBackground called, current thread is = 865 thread name is = AsyncTask #3
02-21 02:49:09.637 3590 3620 E AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
02-21 02:49:09.637 3590 3620 E AndroidRuntime: Process: com.test.weijuncheng.testasynctask, PID: 3590
02-21 02:49:09.637 3590 3620 E AndroidRuntime: java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$SerialExecutor$1@becb756 rejected from java.util.concurrent.ThreadPoolExecutor@62a73d7[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 10]
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2078)
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:843)
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1389)
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at android.os.AsyncTask$SerialExecutor.scheduleNext(AsyncTask.java:258)
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:247)
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
02-21 02:49:09.637 3590 3620 E AndroidRuntime: at java.lang.Thread.run(Thread.java:764)
02-21 02:49:09.645 1268 1865 W ActivityManager: Force finishing activity com.test.weijuncheng.testasynctask/.MainActivity
线程池会拒绝执行FutureTask任务
网友评论