1. AsyncTask介绍
AsyncTask能够适当地、简单地用于 UI线程。 这个类不需要操作线程(handlers)就可以完成后台操作将结果返回UI。
AsyncTask设计目的在于在framework层完成 Thread and Handler交互。Asyn应该被用在短操作上(数秒内完成)。如果需要保持线程运行长时间,相当推荐使用APIs提供的java.util.concurrent例如:Executor
, ThreadPoolExecutor
and FutureTask
.
异步任务的定义是一个在后台线程上运行,其结果是在 UI线程上发布的计算。 异步任务被定义成三种泛型类型: Params,Progress和 Result;和四个步骤:
onPreExecute
doInBackground,
onProgressUpdate
onPostExecute
2. AsyncTask线程池示例
AsyncTask是基于FutureTask封装的异步操作类支持 |
(1)多线程串行模式执行:private ExecutorService SINGLE_TASK = Executors.newSingleThreadExecutor();
(2)多线程限制模式执行:private ExecutorService LIMITED_TASK = Executors.newFixedThreadPool(3);
(3)多线程并行模式执行:private ExecutorService FULL_TASK = Executors.newCachedThreadPool ();
(4)提供查询线程是否取消:isCancelled()
(5)支持线程取消:onCancelled(Result result)
(6)提供获取线程状态:getStatus()
AsyncTask在线程执行层面提供了三种方法 |
(1)#execute()提交任务,按照先后顺序每次只运行一个。
也就是说它是按照提交的次序,每次只启动一个线程执行一个任务,完成之后在执行第二个任务,也就是相当于只有一个后台线程在执行所提交的任务类似于:Executors.newSingleThreadExecutor();
(2)#execute(Runnable runnable)提交任务,按照先后顺序每次只运行一个。参考(1)
(3)#executeOnExecutor(Executor exec, Params... params)
这个接口允许开发者提供自定义的线程池来运行和调度Thread。如果你想让所有的任务都能同时并发运行,那就创建一个没有限制的线程池,参考上述:FULL_TASK,并提供给AsyncTask,这样这个AsyncTask实例就有了自己的线程池而不必使用AsyncTask默认的。同理可以使用LIMITED_TASK。
AsyncTask代码示例 |
代码将线程执行过程转化为可视化效果:
/**
* 线程池二:使用AsyncTask实现线程池控制
*
*
*/
private void initViewAsync() {
setContentView(R.layout. activity_thread_pool);
mBar1 = (SeekBar) findViewById(R.id. seekBar1);
mBar2 = (SeekBar) findViewById(R.id. seekBar2);
mBar3 = (SeekBar) findViewById(R.id. seekBar3);
mBar4 = (SeekBar) findViewById(R.id. seekBar4);
mBar5 = (SeekBar) findViewById(R.id. seekBar5);
mBar6 = (SeekBar) findViewById(R.id. seekBar6);
mBar1.setMax(100);
mBar2.setMax(100);
mBar3.setMax(100);
mBar4.setMax(100);
mBar5.setMax(100);
mBar6.setMax(100);
MyAsynctask asyncTask1 = new MyAsynctask("bar1" );
MyAsynctask asyncTask2 = new MyAsynctask("bar2" );
MyAsynctask asyncTask3 = new MyAsynctask("bar3" );
MyAsynctask asyncTask4 = new MyAsynctask("bar4" );
MyAsynctask asyncTask5 = new MyAsynctask("bar5" );
MyAsynctask asyncTask6 = new MyAsynctask("bar6" );
asyncTask1.executeOnExecutor( FULL_TASK);
asyncTask2.executeOnExecutor( FULL_TASK);
asyncTask3.executeOnExecutor( FULL_TASK);
asyncTask4.executeOnExecutor( FULL_TASK);
asyncTask5.executeOnExecutor( FULL_TASK);
asyncTask6.executeOnExecutor( FULL_TASK);
}
class MyAsynctask extends AsyncTask<Void, Integer, Void> {
private String mKey = null;
public MyAsynctask(String key) {
mKey = key;
}
@Override
protected Void doInBackground(Void... params) {
if ("bar1" .equals(mKey )) {
while (mBar1 .getProgress() < 100) {
int i = mBar1 .getProgress() + 1;
if (0 == i % 10) {
Log. i(TAG, "mBar1 number:" + i );
}
try {
Thread. sleep(mTime);
} catch (InterruptedException e ) {
e.printStackTrace();
}
publishProgress( i);
}
} else if ("bar2" .equals(mKey )) {
while (mBar2 .getProgress() < 100) {
int i = mBar2 .getProgress() + 1;
if (0 == i % 10) {
Log. i(TAG, "mBar2 number:" + i );
}
try {
Thread. sleep(mTime);
} catch (InterruptedException e ) {
e.printStackTrace();
}
publishProgress( i);
}
} else if ("bar3" .equals(mKey )) {
while (mBar3 .getProgress() < 100) {
int i = mBar3 .getProgress() + 1;
if (0 == i % 10) {
Log. i(TAG, "mBar3 number:" + i );
}
try {
Thread. sleep(mTime);
} catch (InterruptedException e ) {
e.printStackTrace();
}
publishProgress( i);
}
} else if ("bar4" .equals(mKey )) {
while (mBar4 .getProgress() < 100) {
int i = mBar4 .getProgress() + 1;
if (0 == i % 10) {
Log. i(TAG, "mBar4 number:" + i );
}
try {
Thread. sleep(mTime);
} catch (InterruptedException e ) {
e.printStackTrace();
}
publishProgress( i);
}
} else if ("bar5" .equals(mKey )) {
while (mBar5 .getProgress() < 100) {
int i = mBar5 .getProgress() + 1;
if (0 == i % 10) {
Log. i(TAG, "mBar5 number:" + i );
}
try {
Thread. sleep(mTime);
} catch (InterruptedException e ) {
e.printStackTrace();
}
publishProgress( i);
}
} else if ("bar6" .equals(mKey )) {
while (mBar6 .getProgress() < 100) {
int i = mBar6 .getProgress() + 1;
if (0 == i % 10) {
Log. i(TAG, "mBar6 number:" + i );
}
try {
Thread. sleep(mTime);
} catch (InterruptedException e ) {
e.printStackTrace();
}
publishProgress( i);
}
}
return null ;
}
@Override
protected void onPostExecute(Void result ) {
Log. i(TAG, "onPostExecute");
}
@Override
protected void onPreExecute() {
Log. i(TAG, "onPreExecute");
}
@Override
protected void onProgressUpdate(Integer... values ) {
if ("bar1" .equals(mKey )) {
mBar1.setProgress( values[0]);
} else if ("bar2" .equals(mKey )) {
mBar2.setProgress( mBar2.getProgress() + 1);
} else if ("bar3" .equals(mKey )) {
mBar3.setProgress( mBar3.getProgress() + 1);
} else if ("bar4" .equals(mKey )) {
mBar4.setProgress( mBar4.getProgress() + 1);
} else if ("bar5" .equals(mKey )) {
mBar5.setProgress( mBar5.getProgress() + 1);
} else if ("bar6" .equals(mKey )) {
mBar6.setProgress( mBar6.getProgress() + 1);
}
}
}
布局文件代码activity_thread_pool.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Task#1"
android:textAppearance="?android:attr/textAppearanceLarge" />
<SeekBar
android:id="@+id/seekBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#dddddd"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Task#2"
android:textAppearance="?android:attr/textAppearanceLarge" />
<SeekBar
android:id="@+id/seekBar2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#dddddd"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Task#3"
android:textAppearance="?android:attr/textAppearanceLarge" />
<SeekBar
android:id="@+id/seekBar3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#dddddd"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Task#4"
android:textAppearance="?android:attr/textAppearanceLarge" />
<SeekBar
android:id="@+id/seekBar4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#dddddd"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Task#5"
android:textAppearance="?android:attr/textAppearanceLarge" />
<SeekBar
android:id="@+id/seekBar5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#dddddd"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="10dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Task#6"
android:textAppearance="?android:attr/textAppearanceLarge" />
<SeekBar
android:id="@+id/seekBar6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1px"
android:background="#dddddd"/>
</LinearLayout>
执行效果:
3. AsyncTask源码分析
3.1变量定义
private static final int CPU_COUNT = Runtime. getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
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);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit. SECONDS, sPoolWorkQueue , sThreadFactory);
/**
* 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();
声明中可以看出,变量THREAD_POOL_EXECUTOR 和sHandler 都为静态变量static,为进程范围内共享的,属于类的作用范围是CLASSPATH,其中一个进程就是一个VM。
声明中可以看出,变量sDefaultExecutor 和mStatus 使用volatile关键字声明,volatile的作用是: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值.
声明中可以看出,变量mCancelled 和mTaskInvoked 类型为AtomicBoolean ,表示可以用原子方式更新的 boolean 值。有关原子变量属性的描述,请参阅 java.util.concurrent.atomic 包规范。AtomicBoolean 可用在应用程序中(如以原子方式更新的标志),但不能用于替换 Boolean。
3.2函数分析
构造函数分析
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
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 );
}
};
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);
}
}
};
}
其中WorkRunnable实现Callable<Result>,可参考上篇博客:线程池二:Java并发编程:Callable、Future和FutureTask中的:使用Callable+FutureTask获取执行结果,call()函数为线程执行函数,将doInBackground()函数放入其中,执行后台函数。
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
执行函数分析
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;
// 线程前执行,UI线程
onPreExecute();
mWorker.mParams = params;
// 执行mFuture
exec.execute(mFuture);
return this;
}
...
// 传递线程执行进度
protected final void publishProgress(Progress... values) {
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
// 结束线程
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
// 线程结束调用
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
// handler处理操作
private static class InternalHandler extends Handler {
@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;
}
}
}
上面代码中可见executeOnExecutor需要在主线程中执行,依次调用:
(1)UI线程调用onPreExecute()
(2)线程中调用doInBackground( mParams)
(3)UI线程调用onProgressUpdate
(4)UI线程调用onPostExecute(result)
4. 参考资料
线程池二:Java并发编程:Callable、Future和FutureTaskhttps://developer.xamarin.com/api/member/Android.OS.Binder.FlushPendingCommands()/