AsyncTask异步任务,方便我们在Android在子线程执行任务,在主线程执行结果,避免ANR。
- AsyncTask基本使用:
public class MainActivity extends AppCompatActivity {
final private static String TAG = "AsyncTask_Test";
private TextView show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
show = (TextView) findViewById(R.id.show);
}
public void download(View view) {
DownloadTask task = new DownloadTask(this);
try {
task.execute(new URL("http://www.jianshu.com/"));
} catch (Exception e) {
e.printStackTrace();
}
}
private class DownloadTask extends AsyncTask<URL, Integer, String> {
ProgressDialog progressDialog;
int hasRead = 0;
Context context;
DownloadTask(Context context) {
this.context = context;
}
@Override
protected String doInBackground(URL... params) {
StringBuilder stringBuilder = new StringBuilder();
try {
URLConnection connection = params[0].openConnection();
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(connection.getInputStream(), "utf-8"));
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
hasRead++;
publishProgress(hasRead);
}
return stringBuilder.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String s) {
show.setText(s);
progressDialog.dismiss();
super.onPostExecute(s);
}
@Override
protected void onPreExecute() {
progressDialog = new ProgressDialog(context);
progressDialog.setTitle("Downloading");
progressDialog.setMessage("Please wait ...");
progressDialog.setCancelable(false);
progressDialog.setMax(202);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setIndeterminate(false);
progressDialog.show();
super.onPreExecute();
}
@Override
protected void onProgressUpdate(Integer... values) {
show.setText("Has read " + values[0] + " lines.");
progressDialog.setProgress(values[0]);
super.onProgressUpdate(values);
}
}
}
- AsyncTask源码分析
我们分析AsyncTask主要分为三步:
- static属性
- 构造函数
- execute方法
2.1 static属性:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
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);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
//线程池的任务队列,任务个数不能超过128,否则会抛出异常,拒绝任务。
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
//----------------------------以上属性为线程池的参数---------------------------
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;
}
//----------------------------线程池初始化---------------------------
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static class SerialExecutor implements Executor {
//任务队列(集成了队列和栈的双重特性)这里使用的是队列
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
//活动任务
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);
}
}
}
//----------------------------执行器初始化---------------------------
2.2 构造函数:
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
* 创建一个新的异步任务,构造函数必须在UI线程中被调用。
*/
public AsyncTask() {
this((Looper) null);
}
/**
* 这个构造函数对我们是隐藏的,不允许被调用
* @hide
*/
public AsyncTask(@Nullable Handler handler) {
this(handler != null ? handler.getLooper() : null);
}
/**
* 这个构造函数对我们是隐藏的,不允许被调用
* @hide
*/
public AsyncTask(@Nullable Looper callbackLooper) {
//我们能用的构造函数只有一个空构造,所以mHandler=UI线程的Handler
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方法。
postResult(result);
}
//任务执行结束返回执行结果。
return result;
}
};
//创建一个future任务,保存工作任务。
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);
}
}
};
}
2.3 execute方法。
/**
* MainThread标记只能在祝线程调用。
**/
@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) {
//判断运行状态是否是PENDING,如果不是抛出异常终止运行,所以一个异步任务对象只能运行一次。
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();
//给工作任务的mParams赋值
mWorker.mParams = params;
//执行器执行任务,此时跳转到sDefaultExecutor的execute方法中执行,并将future任务传过去,执行mFuture的run方法。
exec.execute(mFuture);
return this;
}
/**
* mFuture的run方法。run方法执行工作任务的call方法,call方法执行doInBackground方法。(此时执行的任务在子线程中执行。)
**/
public void run() {
if (state != NEW ||
!U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
return;
try {
//callable就是工作任务(mWorker)。
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
//调用工作任务的call方法,获取执行结果。call方法中执行了doInBackgroud方法,并返回了执行结果。
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
//发生异常后执行的方法。
setException(ex);
}
if (ran)
//顺利执行完成后,执行的方法。
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
//调用了cancle方法(手动中断线程)或线程被中断执行此方法。
handlePossibleCancellationInterrupt(s);
}
}
/**************************************************************************
此时执行结果分为三个分支:
- 顺利执行完成
- 执行时代码发生异常
- 执行时线程被中断
**************************************************************************/
//我们先看前两种情况:顺利执行完成、执行时代码发生异常
protected void set(V v) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = v;
//更改state状态变量为NORMAL(2)
U.putOrderedInt(this, STATE, NORMAL); // final state
//调用finishCompletion方法
finishCompletion();
}
}
protected void setException(Throwable t) {
if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
outcome = t;
//更改state状态变量为EXCEPTIONAL(3)
U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
//调用finishCompletion方法
finishCompletion();
}
}
//可以看到,顺利执行完成、执行时代码发生异常,都调用了finishCompletion方法,只是状态值不一样。
//finishCompletion调用了构造函数中mFuture的done方法
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null;) {
if (U.compareAndSwapObject(this, WAITERS, q, null)) {
for (;;) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
//调用构造函数中mFuture的done方法。
done();
//mFuture中的工作任务置为空
callable = null; // to reduce footprint
}
//mFuture中的done方法在构造函数中(已经贴过了在这就不贴了)done方法调用了postResultIfNotInvoked方法
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
private Result postResult(Result result) {
//通过handler发送消息到主线程,并将结果带过去。
//AsyncTaskResult封装了执行结果和AsyncTask对象。
@SuppressWarnings("unchecked")
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
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:
// 调用AsyncTask中的finish方法。
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
//finish中执行onCancelled,onPostExecute方法。
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
2.4 AsyncTask更新进度条源码解析:
AsyncTask更新进度条需要手动调用publishProgress方法,publishProgress方法发送消息到handler执行AsyncTask对象中的onProgressUpdate方法。
//标记在工作(子)线程中调用
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
总结:
- new AysncTask 和 execute方法,只能在UI线程执行。
- publishProgress只能在工作线程中执行。
- AsyncTask执行器默认是SerialExecutor也就是一个任务一个任务执行,不管线程池中有多少个线程,同时执行的只有一个线程。
建议:AsyncTask中只执行耗时比较少的异步操纵,不要同时执行过多的任务。
注意:
- Activity或者Fragment中不要不要定义非静态的内部类AsyncTask,AsyncTask内部类会持有外部类的隐式引用。由于AsyncTask的生命周期可能比Activity的长,当Activity进行销毁AsyncTask还在执行时,由于AsyncTask持有Activity的引用,导致Activity对象无法回收,进而产生内存泄露。
- Activity重新创建时AsyncTask数据丢失。当Activity销毁并创新创建后,还在运行的AsyncTask会持有一个Activity的非法引用即之前的Activity实例。导致onPostExecute()没有任何作用。
网友评论