让Android应用保持灵敏响应:AsyncTask
2015-11-25 01:30
363 查看
任何可能需要较长时间的操作都不应该放在UI主线程里,而应该创建一个工作线程去处理。当前台Activity未在5秒内对用户点击事件或者BroadcastReceiver接收到广播后未在10秒内返回,Android就会抛出一个应用无响应(ANR)的对话框,以供用户选择是否关闭该应用。
而UI主线程只需要简单地创建一个异步工作线程实例并调用其execute()方法即可:
如果需要更复杂的交互,可以继承Thread或者HandlerThread类。这时,应在自定义的工作线程中调用:
来降低工作线程的优先级。由于新线程的默认优先级与UI主线程一样,因此若不这样设置仍会拖慢应用的响应速度。此外,UI主线程还应提供一个Handler给工作线程回复任务完成情况。
对于在BroadcastReceiver中需要处理长时间操作的情况,可以使用IntentService类。
另外,可以用StrictMode类来监测UI主线程或者其他组件中的长时间操作:
需要注意的是,StrictMode并不保证能发现所有的问题,比如在JNI中的硬盘、网络访问就不一定会触发它。
参考资料:
Android > Develop > Training > Keeping Your App Responsive
https://developer.android.com/intl/zh-cn/training/articles/perf-anr.html
Android > Develop > Reference > AsyncTask
https://developer.android.com/reference/android/os/AsyncTask.html
如何避免ANR?
创建一个处理长时间操作的工作线程的最高效方式是继承AsyncTask类:// 注意:AsyncTask适用于短时间(最多几秒)的操作。 // 如果任务耗时更长,推荐使用java.util.concurrent包中的 // Executor、ThreadPoolExecutor和FutureTask。 // AsyncTask<Params, Progress, Result>的三个类型 // 分别对应参数、进度、结果的数据类型。如若用不着,可用Void代替。 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { // AsyncTask执行流程按调用顺序可分为四步, // 第二步和第四步最常用,用不着的方法可以不Override。 // 第一步:在UI主线程中运行。 @Override protected void onPreExecute() { // 一般用来设置任务相关的UI,比如进度条 } // 第二步:在第一步完成后立马由工作线程运行。 // 参数由UI主线程调用的execute(Params...)方法传进来(见下文), // 返回的参数传递给第四步。 // 可调用publishProgress(Progress...)来把工作进度告知UI主线程, // 后者在第三步中进行响应。 @Override protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); // 告知UI主线程当前的工作进度 publishProgress((int) ((i / (float) count) * 100)); // 当UI主线程调用cancel(false)来取消任务时,尽早退出 if (isCancelled()) break; } return totalSize; } // 第三步:在publishProgress(Progress...)调用后由UI主线程运行。 @Override protected void onProgressUpdate(Integer... progress) { // 显示任务进度 } // 第四步:在第二步(任务)完成后由UI主线程执行。 // 注意:若任务被取消,则不会调用, // 而是会调用后面的onCancelled(Result)方法。 @Override protected void onPostExecute(Long result) { // 当任务完成时的处理代码 showDialog("Downloaded " + result + " bytes"); } // 当任务被取消,并且从第二步返回时,由UI主线程执行。 @Override protected void onCancelled(Long result) { // 可以不实现此方法 } }
而UI主线程只需要简单地创建一个异步工作线程实例并调用其execute()方法即可:
// 创建一个异步工作线程实例。 // 注意:AsyncTask的实例只能由UI主线程创建。 DownloadFilesTask downloadFilesTask = new DownloadFilesTask(); // 注意:此方法只能由UI主线程调用, // 并且只能调用一次,后续调用会抛出异常。 // 若想多次调用,可以另外创建AsyncTask实例再调用。 // 另外,从Android 1.6(API 4)开始,execute方法支持多任务并发。 // 但从Android 3.0(API 11)起,execute方法改为单线程运行, // 新任务加入等待队列,以此避免修改共享资源时冲突 //(AsyncTask并不会也不可能知道怎么帮任务加锁解锁)等问题。 // 如若多任务能避免冲突(在doInBackground方法中处理好锁的问题), // 或者多任务并不会冲突,可调用: // downloadFilesTask.executeOnExecutor(AsyncTask. // THREAD_POOL_EXECUTOR, url1, url2, url3); downloadFilesTask.execute(url1, url2, url3); // 当任务需要取消时调用。 // 参数为true时强制终止工作线程,为false时允许运行中的任务继续运行 //(false时工作线程可以通过调用isCancelled()来得知任务被取消)。 downloadFilesTask.cancel(false);
如果需要更复杂的交互,可以继承Thread或者HandlerThread类。这时,应在自定义的工作线程中调用:
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
来降低工作线程的优先级。由于新线程的默认优先级与UI主线程一样,因此若不这样设置仍会拖慢应用的响应速度。此外,UI主线程还应提供一个Handler给工作线程回复任务完成情况。
对于在BroadcastReceiver中需要处理长时间操作的情况,可以使用IntentService类。
另外,可以用StrictMode类来监测UI主线程或者其他组件中的长时间操作:
public void onCreate() { // 注意仅在开发者版本才做这些检测,发布版本就不必了 if (DEVELOPER_MODE) { // 设置线程检测政策 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() // All包括CustomSlowCalls、DiskReads、DiskWrites、 // Network、ResourceMismatches .detectAll() // 把违规信息显示在系统log中 .penaltyLog() // 创建ThreadPolicy实例 .build()); // 设置虚拟机检测政策 StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() // All包括ActivityLeaks、CleartextNetwork、 // FileUriExposure、LeakedClosableObjects、 // LeakedRegistrationObjects、LeakedSqlLiteObjects .detectAll() // 把违规信息显示在系统log中 .penaltyLog() // 创建VmPolicy实例 .build()); } super.onCreate(); }
需要注意的是,StrictMode并不保证能发现所有的问题,比如在JNI中的硬盘、网络访问就不一定会触发它。
参考资料:
Android > Develop > Training > Keeping Your App Responsive
https://developer.android.com/intl/zh-cn/training/articles/perf-anr.html
Android > Develop > Reference > AsyncTask
https://developer.android.com/reference/android/os/AsyncTask.html
相关文章推荐
- Android中AsyncTask的用法实例分享
- Android的异步任务AsyncTask详解
- asynctask的用法详解
- Android中AsyncTask详细介绍
- Android中AsyncTask与handler用法实例分析
- Android开发笔记之:AsyncTask的应用详解
- android教程之使用asynctask在后台运行耗时任务
- 自定义可以下拉刷新的listview
- Android中的异步任务——AsyncTask
- Android中AsyncTask的简单用法
- 深入解析AsyncTask
- android AsyncTask介绍
- Android 网络通信框架Volley简介
- Android实战技巧:深入解析AsyncTask
- Android的线程使用来更新UI----Thread、Handler、Looper、Time...
- AsyncTask简单入门
- android异步操作AsyncTask编写文件查看器
- Android的AsyncTask类的简单教程
- Android异步任务(AsyncTask)的设计思想
- AsyncTask(1)一个使用AsyncTask实现简单异步刷新的功能。