每天一篇系列:
强化知识体系,查漏补缺。
欢迎指正,共同学习!
AsynTask是Android提供的一个轻量级异步任务类。
比如写一个异步下载应用APK的AsynTask,源码如下:
class ApkDownloadTask extends AsyncTask<String, Integer, Boolean>{
private String filepath;
private String packagename;
public ApkDownloadTask(String filepath,String packagename){
this.filepath = filepath;
this.packagename = packagename;
}
@Override
protected Boolean doInBackground(String... params) {
// TODO Auto-generated method stub
publishProgress(0);
HttpURLConnection conn = null;
String url;
InputStream stream = null;
FileOutputStream fileOutputStream = null;
File file = null;
try {
url = params[0];
file = new File(filepath);
if (file.exists()) {
file.delete();
}
fileOutputStream = new FileOutputStream(file);
conn = HttpUtil.createDownloadConnection(url, 0);
byte[] bytes = new byte[1024];
if (conn == null) {
return false;
}
int contentLen = conn.getContentLength();
stream = conn.getInputStream();
int readLen = 0;
int downloadsize = 0;
int index = 0;
while (true) {
readLen = stream.read(bytes);
downloadsize += readLen;
if(readLen <= 0){
break;
}
fileOutputStream.write(bytes, 0, readLen);
fileOutputStream.flush();
//20KB update UI
if((index%20) == 0){
publishProgress((int)((downloadsize*100.0f)/contentLen));
}
index++;
}
publishProgress(100);
}catch (Exception e) {
DebugUtil.Debug(DebugUtil.DEBUG_TVPosterCell,TAG, e.toString());
return false;
}finally {
try {
if (stream != null) {
stream.close();
}
if (conn != null) {
conn.disconnect();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
DebugUtil.Debug(DebugUtil.DEBUG_TVPosterCell,TAG, e.toString());
return false;
}
}
return true;
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
DownloadChangeEvent(values[0],true);
}
@Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if(!result){
Intent intent = new Intent();
intent.setAction("com.blinds.launcher.download.fail");
mContext.sendBroadcast(intent);
DownloadChangeEvent(0,false);
return;
}
//2.install
FileUtil.chmodFile(filepath);
//AppUtil.getInstance(mContext).installApk(filepath);
AppUtil.getInstance(mContext).installApkPeaceful(filepath,packagename, new AppUtil.ApkInstallObserver(){
//delect the apk when install callback ? or delect files when aplication init
@Override
public void packageInstalled(String packagename,int resultcode){
try {
super.packageInstalled(packagename, resultcode);
if(resultcode == PackageManager.INSTALL_SUCCEEDED){
DebugUtil.Debug(DebugUtil.DEBUG_TVPosterCell,TAG, "-------------->postercell install apk sucess:"+packagename);
//3.start apk
//doJump2APK();
//toast install success
Intent intent = new Intent();
intent.setAction("com.blinds.launcher.install.success");
mContext.sendBroadcast(intent);
return;
}
} catch (Exception e) {
DebugUtil.Debug(DebugUtil.DEBUG_TVPosterCell,TAG, "-------------->packageInstalled :"+e);
}
DebugUtil.Debug(DebugUtil.DEBUG_TVPosterCell,TAG, "-------------->postercell install apk fail:"+packagename+" return code:"+resultcode);
//toast install fail
Intent intent = new Intent();
intent.setAction("com.blinds.launcher.install.fail");
mContext.sendBroadcast(intent);
}
});
}
}
其中,doInBackground在新的线程中作耗时任务(比如说下载文件),并且还可以通过publishProgress随时通知下载进度,而onPostExecute是在UI线程中回调的,因此可以处理UI事件。
启动AsynTask代码如下:
ApkDownloadTask downloadTask = new ApkDownloadTask(apkFilePath, packageName);
downloadTask.execute(apk_downloadurl);
既然知道AsynTask如何使用了,那么从源码的角度来看一看AsynTask是如何实现的。
public abstract class AsyncTask<Params, Progress, Result> {
...
private static final InternalHandler sHandler = new InternalHandler();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
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();
...
/**
* 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
return postResult(doInBackground(mParams));
}
};
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 occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
...
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;
}
}
}
...
}
在AsyncTask的构造函数中创建了两个任务类WorkerRunnable、FutureTask,并且AsyncTask内部创建了一个Handler,注意这个Handler并没有使用其他线程的Looper,而是使用了创建AsyncTask的线程的Looper,也就是说如果在UI线程创建了AsyncTask,那么这个Handler的Looper还是UI线程的Looper。
WorkerRunnable实现了Callable的接口,是用来实际执行doInBackground任务,并且把执行结果通过Handler转发:
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {
Params[] mParams;
}
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
doInBackground是抽象方法,利用继承的特性,子类继承该方法后,可以完成耗时操作的处理。
FutureTask实现Future,Runnable类,充当Runnable的角色,执行异步操作的功能。
public final Result get() throws InterruptedException, ExecutionException {
return mFuture.get();
}
private void postResultIfNotInvoked(Result result) {
//因为是原子操作,保证任务的安全性
final boolean wasTaskInvoked = mTaskInvoked.get();
if (!wasTaskInvoked) {
postResult(result);
}
}
以上只是粗略的了解AsyncTask相关属性和方法。
在应用中使用AsyncTask有以下几种方式execute,我们分别来分析:
public static void execute(Runnable runnable) {
sDefaultExecutor.execute(runnable);
}
在AsyncTask中有一个默认的线程池:
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
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);
}
}
}
线程池通过ThreadPoolExecutor创建,SerialExecutor实现了Executor接口,对内部方法添加了synchronized,把新的Runnable任务每次添加到队列尾,每次把队列中的首个任务放置到线程池中执行,因此实际上默认任务是串行执行的。
而另外的方法如下:
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}
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();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
实现上作了状态安全检查,另外回调了onPreExecute(),注意这里还是在创建者线程内,所以如果在UI线程创建的AsyncTask,那么onPreExecute()就是在UI线程中,子类就可以继承onPreExecute()并处理需要做的事情。而这里把参数params赋值给WorkerRunnable,把FutureTask作为了SerialExecutor的参数,也就是说会把FutureTask丢入到线程池中,可以看到WorkerRunnable是FutureTask实际需要执行的任务,根据WorkerRunnable的定义,doInBackground是在新的工作线程中处理的,因此不会阻塞主线程,实现异步处理。
再看看publishProgress的处理:
protected final void publishProgress(Progress... values) {
//这里有一个原子操作的处理
if (!isCancelled()) {
sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
new AsyncTaskResult<Progress>(this, values)).sendToTarget();
}
}
直接使用了工作线程的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;
}
}
}
AsyncTaskResult是AsyncTask的内部类,用来保存Task任务和与之对应的数据,而在发消息时指向的mTask都是this:
@SuppressWarnings({"RawUseOfParameterizedType"})
private static class AsyncTaskResult<Data> {
final AsyncTask mTask;
final Data[] mData;
AsyncTaskResult(AsyncTask task, Data... data) {
mTask = task;
mData = data;
}
}
}
所以根据消息任务的处理,可以看到调用publishProgress会通过Handler中转再回调onProgressUpdate,子类在继承AsyncTask重写onProgressUpdate就可以获得进度信息。
而耗时任务结束后会通过Handler中转再回调finish方法:
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
根据状态的检查,如果是用户cancle的,将会回调onCancelled方法,而正常结束的处理将会回调onPostExecute方法,因为都是在Handler内部回调的,因此onProgressUpdate、onCancelled和onPostExecute都在工作在创建AsyncTask线程,所以通常我们在UI线程创建了AsyncTask,在onProgressUpdate、onCancelled和onPostExecute都可以处理UI控件的变化。
网友评论