Asynchronous Android读书笔记二Staying Responsive with AsyncTask
来源:互联网 发布:阿里云服务器学生9块 编辑:程序博客网 时间:2024/05/12 19:16
Introducing AsyncTask
If we invoke AsyncTask's cancel method before doInBackground completes,onPostExecute will not be called. Instead, the alternative onCancelled callback method is invoked so that we can implement different behavior for a successful versus cancelled completion.
1、 AsyncTask的本质是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。
2、线程池中的工作线程执行doInBackground(mParams)方法执行异步任务
3、当任务状态改变之后,工作线程会向UI线程发送消息,AsyncTask内部的InternalHandler响应这些消息,并调用相关的回调函数
Declaring AsyncTasktypes
public class PrimesTask extends AsyncTask<Integer, Integer, BigInteger> {
private TextView resultView;
public PrimesTask(TextView resultView) { this.resultView = resultView;
}
@Override protected BigInteger doInBackground(Integer... params) {
int n = params[0]; BigInteger prime = new BigInteger("2"); for (int i=0; i<n; i++) {
prime = prime.nextProbablePrime(); }
return prime; }
@Override protected void onPostExecute(BigInteger result) {
resultView.setText(result.toString()); }
}
Executing AsyncTasks
new PrimesTask(resultView).execute(500);
params for: doInBackground(Integer... params)
Providing feedback to the user
handle with:
onPreExecute()
onPostExecute(BigInteger result)
Providing progress updates
doInBackground(Integer... params) {
publishProgress(percent);
}
onProgressUpdate(Integer... values) {
progress.setProgress(values[0]); }
Canceling AsyncTasks
public final boolean cancel(boolean mayInterruptIfRunning)
Simply invoking cancel is not sufficient to cause our task to finish early. We need to actively support cancellation by periodically checking the value returned from isCancelled and reacting appropriately in doInBackground.
instead of onPostExecuteprotected BigInteger doInBackground(Integer... params) { int primeToFind = params[0]; BigInteger prime = new BigInteger("2"); for (int i=0; i<primeToFind; i++) {
prime = prime.nextProbablePrime();
int percentComplete = (int)((i * 100f)/primeToFind);publishProgress(percentComplete);
if (isCancelled())break;
}
return prime; }
we have the opportunity to implement different behavior for a cancelled executionby implementingonCancelled. There are two variants of this callback method:
//If we are performing an incremental computation in our AsyncTask
protected void onCancelled(Result result);
//If AsyncTask can provide either a complete result (such as a fully downloadedimage) or nothing, then we will probably want to override the zero argu///mentonCancelled() method.
protected void onCancelled();
Handling exceptions
For the callback methods that run on the main thread—onPreExecute,onProgressUpdate,onPostExecute, and onCancelled—we can catch exceptionsin the method and directly update the user interface to alert the user.
Of course, exceptions are likely to arise in our doInBackground method too, as this is where the bulk of the work of AsyncTask is done, but unfortunately, we can't update the user interface from doInBackground. A simple solution is to have doInBackground return an object that may contain either the result or an exception, as follows:
@Override protected final Result<T> doInBackground(Void... params) {
Result<T> result = new Result<T>(); try {
result.actual = calculateResult(); } catch (Exception exc) {
result.exc = exc; }
return result; }
protected abstract T calculateResult() throws Exception;
Now we can check inonPostExecute for the presence of an Exception in the Result object. If there is one, we can deal with it, perhaps by alerting the user;otherwise, we just use the actual result as normal.
@Override protected final void onPostExecute(Result<R> result) {
if (result.exc != null) { // ... alert the user ...
} else { // ... success, continue as normal ...
}}
Controlling the level of concurrency
1.The original goal of AsyncTask was to help developers avoid blocking the main thread. In its initial form at API level 3, AsyncTasks were queued and executed serially (that is, one after the other) on a single background thread, guaranteeing that they would complete in the order they were started.
2.This changed in API level 4 to use a pool of up to 128 threads to execute multiple AsyncTasks concurrently with each other—a level of concurrency of up to 128. So there are no guarantees that AsyncTasks will complete in the same order they were started
3.As a result, a further change was made at API level 11, switching back to serial execution by default, and introducing a new method that gives concurrency control back to the app developer:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params)
Implementations of Executor may run tasks sequentially using a single thread(SERIAL_EXECUTOR)
,use a limited pool of threads to control the level of concurrency, or even directly create a new thread for each task. (THREAD_POOL_EXECUTOR: This Executor runs tasks using a pool of threads for efficiency (starting a new thread comes with some overhead cost that can be avoided through pooling and reuse).THREAD_POOL_EXECUTOR is an instance of the JDK class ThreadPoolExecutor, which uses a pool of threads that grows and shrinks with demand. In the case of AsyncTask, the pool is configured to maintain at least five threads, and expands up to 128 threads. )
As the default behavior of execute since API level 11 is to run AsyncTasks serially on a single background thread, the following two statements are equivalent:
task.execute(params); task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, params);
Besides the default executors provided by AsyncTask, we can choose to create our own. For example, we might want to allow some concurrency by operating off a small pool of threads, and allow many tasks to be queued if all threads are currently busy.
This is easily achieved by configuring our own instance ofThreadPoolExecutoras a static member of one of our own classes—for example, our Activity class.Here's how we might configure an executor with a pool of four to eight threads and an effectively infinite queue:
private static final Queue<Runnable> QUEUE = new LinkedBlockingQueue<Runnable>();
public static final Executor MY_EXECUTOR = new ThreadPoolExecutor(4, 8, 1, TimeUnit.MINUTES, QUEUE);
The parameters to the constructor indicate the core pool size (4), the maximum poolsize (8), the time for which idle additional threads may live in the pool before being removed (1), the unit of time (minutes), and the queue to use when the pool threads are busy.
Using our own Executor is then as simple as invoking our AsyncTaskas follows:task.executeOnExecutor(MY_EXECUTOR, params);
Common AsyncTask issues
Fragmentation issues
1.The most obvious approach is to deliberately target devices running at least Honeycomb, by setting a minSdkVersion of 11 in the Android Manifestfile.
2.A second option is to design our code carefully and test exhaustively on a range
of devices
3.A third solution that has been suggested by the Android development community isto reimplementAsyncTaskin a package within your own project, then extend yourownAsyncTaskclass instead of the SDK version.
1.If we continue processing a background task after the Activity has finished, we areprobably doing unnecessary work, and therefore wasting CPU and other resources(including battery life), which could be put to better use.Activity lifecycle issues
2.Also, any object references held by theAsyncTaskwill not be eligible for garbagecollection until the task explicitly nulls those references or completes and is itselfeligible forGC(garbage collection). Since ourAsyncTaskprobably references theActivity or parts of theViewhierarchy, we can easily leak a significant amount ofmemory in this way.
Handling lifecycle issues with early cancellation
The most appropriate Activitylifecycle method for this isonPause, which is guaranteed to be called before theActivity finishes.
protected void onPause() { super.onPause(); if ((task != null) && (isFinishing()))
task.cancel(false); }
Handling lifecycle issues with retained headlessfragments
A Fragmentthat does not manage a view of its own is known as a headlessFragment.
public class PrimesFragment extends Fragment { private AsyncListener<Integer,BigInteger> listener; private PrimesTask task; public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); setRetainInstance(true); task = new PrimesTask(); task.execute(2000);
}
public void onAttach(Activity activity) { super.onAttach(activity); listener = (AsyncListener<Integer,BigInteger>)activity;
}
public void onDetach() { super.onDetach(); listener = null;
}
class PrimesTask
extends AsyncTask<Integer, Integer, BigInteger>{
protected void onPreExecute() { if (listener != null) listener.onPreExecute(); }
protected void onProgressUpdate(Integer... values) { if (listener != null)
listener.onProgressUpdate(values); }
protected void onPostExecute(BigInteger result) { if (listener != null)
listener.onPostExecute(result); }
protected void onCancelled(BigInteger result) { if (listener != null)
listener.onCancelled(result); }
// ... doInBackground elided for brevity ... }
}
}
We're using the Fragmentlifecycle methods (onAttachandonDetach) to add or remove the currentActivityas a listener, andPrimesTaskdelegates directly to it from all of its main-thread callbacks.
Applications of AsyncTask
Good candidate applications forAsyncTasktend to be relatively short-livedoperations (at most, for a second or two), which pertain directly to a specificFragmentorActivityand need to update its user interface.
AsyncTask is ideal for running short, CPU-intensive tasks, such as numbercrunching or searching for words in large text strings, moving them off the mainthread so that it can remain responsive to input and maintain high frame rates.
Blocking I/O operations such as reading and writing text files, or loading imagesfrom local files withBitmapFactory, are also good use cases forAsyncTask.
Taking these things into account, and the rate at which complexity increases as wetry to deal with them (for example, retained headless fragments!),AsyncTaskstartsto lose its shine for longer operations.
- Asynchronous Android读书笔记二Staying Responsive with AsyncTask
- Asynchronous Android读书笔记四Asynchronous I/O with Loader
- Asynchronous Android读书笔记三Distributing Work with Handler and HandlerThread
- Asynchronous Android读书笔记五Queuing Work with IntentService
- Asynchronous Android读书笔记六Long-running Tasks with Service
- iOS 9: Staying Organized with Storyboard References
- FCC学习笔记-(二) Responsive Design with Bootstrap
- Responsive Design with Bootstrap
- Android之AsyncTask(二)
- 7-3 系统繁忙时的响应(Staying Responsive During Intensive Processing)
- 系统繁忙时的响应(Staying Responsive During Intensive Processing)
- Asynchronous Replication with NexentaStor
- Asynchronous Replication with NexentaStor
- Android AsyncTask testing with Android Test Framework
- Responsive Design with Twitter Bootstrap
- Android - Handler 、AsyncTask(二)
- asynchronous@tornado 记录二
- (续二)Asynchronous JavaScript and XML (AJAX) with Java 2 Enterprise Edition
- hdoj 1316 How Many Fibs? 【Java大数】+【打表】
- apue 第四章
- centos离线安装无线网卡驱动(没有安装成功)
- 求最长单调递减子序列
- ASP.NET总结——静态网页与动态网页
- Asynchronous Android读书笔记二Staying Responsive with AsyncTask
- today
- 为什么需要软件设计过程:一个形象隐喻——房屋建设
- 哈夫曼树(java实现)
- Shared nothing architecture简介
- 简单实现动态展示view布局元素
- xode6 beta版本开发swift 时"Developer tools access" 需控制另一个进程才能继续调试 解决方案
- Ubuntu 之 Sources
- ZOJ - 3818 Pretty Poem