Android之AsynTask
1.asynctask是Android为我们封装的一个异步线程调用的类;首先我们看一下它的简单使用
public class HandleActivity extends AppCompatActivity {
public static final int MSG_CODE = 0;
public static final int MSG_CODE2 = 1;
public static final String TAG = "HandleActivity";
private TextView tv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tv1);
asyncTask.execute();
tv.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
asyncTask.cancel(false);
}
});
}
private AsyncTask asyncTask = new AsyncTask() {
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.d(TAG, "onPreExecute调用了");
tv.setText("准备加载");
}
@Override
protected Object doInBackground(Object[] objects) {
Log.d(TAG, "doInBackground调用了");
try {
int count = 0;
int length = 1;
while (count < 99) {
count += length;
// 可调用publishProgress()显示进度, 之后将执行onProgressUpdate()
publishProgress(count);
// 模拟耗时任务
Thread.sleep(50);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Object[] values) {
super.onProgressUpdate(values);
Log.d(TAG, "onProgressUpdate调用了");
tv.setText("loading..." + values[0] + "%");
}
@Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
Log.d(TAG, "onPostExecute调用了");
tv.setText("加载完成");
}
@Override
protected void onCancelled() {
super.onCancelled();
Log.d(TAG, "onCancelled调用了");
tv.setText("取消加载");
}
};
}
我这里是直接new了一个asynctask对象,当然你也可以写一个类专门继承自Async task,使用的时候new出来即可;
我们可以看到,这里面重写了几个方法,这几个方法都是我们有可能用到的;其中doInBackground是在子线程中运行的,其他的方法都是在主线程中运行的,也就是都可以用来更新ui操作。调用方法asyncTask.execute()必须在主线程中调用。
2.源码分析
2.1,首先看构造方法:
public AsyncTask() {
this((Looper) null);
}
我们接着往下追踪:
public AsyncTask(@Nullable Looper callbackLooper) {
//1.初始化handler;我们一般传进来是空,就会调用getMainHandler(),获取到主线程的handler
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
//2.workerrunnable其实就是一个callback,里面就执行了doInBackground方法
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;
}
};
//3.futuretask其实就是一个runnable
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);
}
}
};
}
其实构造方法里面就是做了一些初始化工作:初始化handler、一个callback对象、一个runnable对象;
接下来,我们再来看调用:
@MainThread
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
注意:@MainThread 源码中已经标记好了,此方法必须在主线程中调用。
executeOnExecutor(sDefaultExecutor, params);这个sDefaultExecutor是什么呢?
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
可以看到就是一个serialExecutor:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();//双向队列
Runnable mActive;//当前正在执行的runnable
public synchronized void execute(final Runnable r) {
//把runnable任务加入队列
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);//把任务交给线程池去执行
}
}
}
可以看到serialExecutor中重写了excute方法;通过上面的注释,可以知道任务在向队列中添加时,是串行的;并且任务被线程池来执行了;那我们去看看这个线程池是什么:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 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);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
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;
}
可以看到这块代码就是来初始化静态线程池的;其中根据CPU核心数,规定了线程池核心线程数,最大线程数,空闲线程存活时间等等。
也就是说明了,我们的异步任务最终是交由这个静态线程池来处理的。
3.我们来过一下这个流程:
asyncTask.execute();------>
executeOnExecutor(sDefaultExecutor, params);----------->
onPreExecute();//开始异步任务之前的准备工作,我们会重写这个方法
exec.execute(mFuture);mFuture就是构造方法中封装了mworker对象的实例------------------>
THREAD_POOL_EXECUTOR.execute(mActive);mActive就是上面的mFuture;mFuture里面装配的是mworker;也就是会执行mworker里面的call方法--------------------->
result = doInBackground(mParams);//开始执行异步任务,有返回结果
postResult(result);----------------->
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget();//其实就是调用了handler发送消息--------------->
switch (msg.what) {
case MESSAGE_POST_RESULT:
result.mTask.finish(result.mData[0]); //finish方法,
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData); //更新进度就是在这里调用的
break;
}------------>
finish方法: if (isCancelled()) { onCancelled(result);//取消任务 } else { onPostExecute(result);//任务完成 }
我们可以看到重写的方法都一步步调用完成;之所以onProgressUpdate、onCancelled、onPostExecute可以直接更新ui,就是因为内部使用了handler机制;
此外,如果我们想使用onProgressUpdate来更新进度,必须要手都调用一个方法:
@WorkerThread
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
getHandler().obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
可以看到上面的注解:@WorkerThread 需要在工作线程调用即可,也就是通常会写到doInBackground方法中;它也是使用的handler发送消息,可以让我们在onProgressUpdate中直接更新ui;
4.总结
asynctask使用的是:一个SerialExecutor,一个ThreadPoolExecutor,一个内部的InternalHandler。执行任务也使用到了Callable
和FutureTask(FutureTask<V> implements RunnableFuture<V>)。
注意:asynctask内部把任务添加到任务队列是串行的,然后再把任务从队列中取出来执行;
上一篇: java集合(一)—数据结构详解
下一篇: 关于浮点数的那些事