AsyncTask学习笔记
来源:互联网 发布:sql server c# output 编辑:程序博客网 时间:2024/06/05 07:34
1)AsyncTask 用法
public abstract class AsyncTask<Params, Progress, Result> { .....................}
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"); } }
由上述代码可知,AsyncTask是抽象类,需要类去继承并且子类需要指定3个泛型,它们分别对应doInBackground(),onProgressUpdate(),onPostExecute()的参数类型。它的核心方法:onPreExecute(),doInBackground(),onProgressUpdate(),onPostExecute(),publishProgress(),
这其中只有doInBackground()是在子线程执行,其余都在主线程中执行。
2)执行的顺序:
onPreExecute()–>doInBackground()–>publishProgress()onProgressUpdate()–>onPostExecute()
- onPreExecute()
这个方法会在后台任务开始执行之间调用,用于进行一些界面上的初始化操作,比如显示一个进度条对话框等。 - doInBackground(Params…)
这个方法中的所有代码都会在子线程中运行,我们应该在这里去处理所有的耗时任务。任务一旦完成就可以通过return语句来将任务的执行结果进行返回,如果AsyncTask的第三个泛型参数指定的是Void,就可以不返回任务执行结果。注意,在这个方法中是不可以进行UI操作的,如果需要更新UI元素,比如说反馈当前任务的执行进度,可以调用publishProgress(Progress…)方法来完成。 - onProgressUpdate(Progress…)
当在后台任务中调用了publishProgress(Progress…)方法后,这个方法就很快会被调用,方法中携带的参数就是在后台任务中传递过来的。在这个方法中可以对UI进行操作,利用参数中的数值就可以对界面元素进行相应的更新。 - onPostExecute(Result)
当后台任务执行完毕并通过return语句进行返回时,这个方法就很快会被调用。返回的数据会作为参数传递到此方法中,可以利用返回的数据来进行一些UI操作,比如说提醒任务执行的结果,以及关闭掉进度条对话框等。
3)AsyncTask 源码分析
1.从execute()开始:
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }
调用了executeOnExecutor(sDefaultExecutor, params)方法。
2.executeOnExecutor(sDefaultExecutor, params)
@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(); mWorker.mParams = params; /*重头戏,核心 *exec是什么? *mFuture是什么?runnable? */ exec.execute(mFuture); return this; }
由上可知,当前任务状态为RUNNING时,再次调用executeOnExecutor()会抛出IllegalStateException(“当前任务已经在执行”),当前任务状态为时FINISHED时,同样会抛出IllegalStateException异常,因为在AsyncTask中一个任务只能执行一次即使执行过程中被cancell掉 往下看调用了onPreExecute(),然后mWorker,mFuture是什么?先不管,再往后 exec.execute(mFuture),终于执行任务了。
3.exec是什么?
exec是我们传进来的sDefaultExecutor,那么sDefaultExecutor是什么?
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;public static final Executor SERIAL_EXECUTOR = new SerialExecutor();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); } } }
到这可以得知sDefaultExecutor 其实是一个SerialExecutor 对象,调用它的execute(Runnable r)方法的时候,会调用ArrayDeque的offer()方法将传入的Runnable对象添加到队列的尾部,然后判断mActive对象是不是等于null,第一次运行当然是等于null了,于是会调用scheduleNext()方法。在这个方法中ArrayDeque的poll()会从队列的头部取值,并赋值给mActive对象,然后调用THREAD_POOL_EXECUTOR去执行取出的取出的Runnable对象。之后如何又有新的任务被执行,同样还会调用offer()方法将传入的Runnable添加到队列的尾部,但是再去给mActive对象做非空检查的时候就会发现mActive对象已经不再是null了,于是就不会再调用scheduleNext()方法。而是在finally语句块中调用了scheduleNext()方法。SerialExecutor 作用是让线程池严格的按照任务添加的顺序执行,一个结束,一个开始。
4.mFuture,mWorker是什么?
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); } } }; }
mFuture 是一个FutureTask对象,实现了RunnableFuture接口,mWorker 是一个WorkerRunnable对象,实现了Callable接口。
FutureTask类:
public class FutureTask<V> implements RunnableFuture<V> { public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; // ensure visibility of callable }}
现在来看FutureTask的run()方法
public void run() { if (state != NEW || !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread())) return; try { //c就是传入的mWorker Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { //执行mWorker的call()方法 result = c.call(); //将ran设置为true ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } //ran为true执行set(result); if (ran) set(result); } } finally { runner = null; int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
由上可知在FutureTask的run()方法中调用了mWorker的call()方法,现在我们来看mWorker的run()
mWorker = new WorkerRunnable<Params, Result>() { public Result call() throws Exception { ........ //noinspection unchecked Result result = doInBackground(mParams); Binder.flushPendingCommands(); return postResult(result); } };
doInBackground()方法被调用,再由postResult(result)将结果返回
private Result postResult(Result result) { @SuppressWarnings("unchecked")Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT, new AsyncTaskResult<Result>(this, result)); message.sendToTarget(); return result; } private static Handler getHandler() { synchronized (AsyncTask.class) { if (sHandler == null) { sHandler = new InternalHandler(); } return sHandler; } } private static class InternalHandler extends Handler { public InternalHandler() { super(Looper.getMainLooper()); } @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:// onProgressUpdate在此调用 result.mTask.onProgressUpdate(result.mData); break; } } }@WorkerThreadprotected final void publishProgress(Progress... values) { if (!isCancelled()) { getHandler().obtainMessage(MESSAGE_POST_PROGRESS, new AsyncTaskResult<Progress>(this, values)).sendToTarget(); } }
这段代码就是一个handler发送消息和接收消息的过程。
当msg.what==MESSAGE_POST_PROGRESS时,调用onProgressUpdate()方法,信息源是来自publishProgress()方法,正因如此,在doInBackground()方法中调用publishProgress()方法才可以从子线程切换到UI线程,从而完成对UI元素的更新操作。
当MESSAGE_POST_RESULT时, result.mTask就是AsyncTask,调用他的finish()方法,在这里调用了 onPostExecute(result)。
private void finish(Result result) { if (isCancelled()) { onCancelled(result); } else { onPostExecute(result); } mStatus = Status.FINISHED; }
到这mWorker 的run()执行完了,那么mFuture 的done()什么时候执行?回到FutureTask.run()方法,
//ran为true执行set(result); if (ran) set(result);
mFuture 的 set(result);
protected void set(V v) { if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) { outcome = v; U.putOrderedInt(this, STATE, NORMAL); // final state //注意这里 finishCompletion(); } } private void finishCompletion() { ..............此处省略 //执行done() done(); ..............此处省略 }
4)AsyncTask缺陷与解决
1.AsyncTask类包含一个全局静态的线程池THREAD_POOL_EXECUTOR,线程池的配置参数如下:
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 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);
当线程池中已有线程个数达到MAXIMUM_POOL_SIZE ,并且缓冲队列已满,如果此时在向线程提交任务,将会抛出RejectedExecutionException
解决方案:替换默认的RejectedExecutionHandler使用
ThreadPoolExecutor.DiscardOldestPolicy()代替。
在调用executeOnExecutor替换线程池。
注意:根据需求合理的选择和设置线程池。
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());
public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }}
2.AsyncTask与他所在的activity 的生命周期不是一致的,activity 终止,AsyncTask并不会终止,它会以它自有的方式继续运行,即使你退出了整个应用程序,AsyncTask提前结束的唯一方法是通过调用AsyncTask.cancel()进行取消。由于不必要的后台线程会导致app阻塞的风险,或者内存泄露。当不再需要一个AsyncTask时,一定要取消它,防止在app执行期间引起任何问题。
而且即使调用了cancel() , 也未必能真正地取消任务。因为如果在doInBackgroud里有一个不可中断的操作,比如BitmapFactory.decodeStream(),那么这个操作会继续下去。
3.AsyncTask内存泄漏
如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。
非静态内部类或非静态匿名类会隐式的持有外部类的引用,外部类就有可能发生泄漏。
4.屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。
5)AsyncTask使用注意事项
1.Task的实例必须在UI thread中创建。
/* Creates a new asynchronous task. This constructor must be *invoked on the UI thread. */ public AsyncTask() { ........省略}
2.. execute方法必须在UI thread中调用 。( @MainThread修饰的方法必须在主线程调用)
@MainThread public final AsyncTask<Params, Progress, Result> execute(Params... params) { return executeOnExecutor(sDefaultExecutor, params); }`
3.不要手动的去调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法 .
4. 一个AsyncTask对象只能执行一次,否则会有异常抛出”java.lang.IllegalStateException: Cannot execute task: the task is already running”。
5. doInBackground()方法并不是在onPreExecute()方法做完全部操作才开始执行。
参考:http://blog.csdn.net/hitlion2008/article/details/7983449
- Android学习笔记---AsyncTask
- Android AsyncTask学习笔记
- AsyncTask学习笔记
- AsyncTask学习笔记
- AsyncTask学习笔记
- AsyncTask学习笔记
- AsyncTask学习笔记
- AsyncTask学习笔记
- AsyncTask学习笔记
- AsyncTask学习笔记
- Android学习笔记之AsyncTask
- android 学习笔记 使用AsyncTask
- android学习笔记(七)AsyncTask
- Android应用开发学习笔记之AsyncTask
- android学习笔记1: AsyncTask使用
- Android学习笔记(39):异步任务AsyncTask
- Android学习笔记1-AsyncTask的用法
- Android之AsyncTask的学习笔记
- 自适应和响应式的区别
- GPL协议
- 从零开始学Scala系列(五)之集合2--Set和Map
- 重叠相加法&重叠保留法
- CSS基本语法 和 样式规则
- AsyncTask学习笔记
- more effective C++条款五解析
- Java在操作ArrayList、HashMap、TreeMap等容器类时,遇到了java.util.ConcurrentModificationException异常
- 一种基于时空特征及有监督学习的医学图像分类方法:Automatic apical view classfication of echocardiograms using a ...
- DNA sequence HDU
- String s =new String()分析堆与栈 创建了几个对象
- finereport帮助文档中期学习总结
- 文件上传下载
- 诸神之战|福建赛区圆满收官,IP“论剑”引爆现场