曾看见有人说过。认为非常有道理。分享一下:

  技术分为术和道两种:

  (1)具体做事的方法是术。

  (2)做事的原理和原则是道。

近期项目发现个重大问题。结果打log跟踪查是AsyncTask导致的。假设对AsyncTask了解的不够深入透彻。那写代码就是埋雷。以后不定在哪个时间爆炸。首先我们要了解,谷歌为什么发明AsyncTask,AsyncTask究竟是用来解决什么问题的?Android有一个原则---单线程模型的原则:UI操作并非线程安全的并且这些操作必须在UI线程中运行。

所以谷歌就制造AsyncTask,AsyncTask扩展Thread增强了与主线程的交互的能力。

假设你的应用没有与主线程交互。那么就直接使用Thread就好了。

在单线程模型中始终要记住两条法则:
1. 不要堵塞UI线程
2. 确保仅仅在UI线程中訪问Android UI工具包

首先来说说AsyncTask重写的4个方法:

(1)doInBackground()  //运行在后台线程中

(2)onPreExecute()  //运行在UI线程中

(3)onProgressUpdate()  //运行在UI线程中

(4)onPostExecute()  //运行在UI线程中

具体的这几个方法怎么使用,具体不清楚的能够谷歌一下,好多同仁讲的好具体的。

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:
1) Task的实例必须在UI thread中创建
2) execute方法必须在UI thread中调用
3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params…), onProgressUpdate(Progress…)这几个方法
4) 该task仅仅能被运行一次,否则多次调用时将会出现异常
doInBackground方法和onPostExecute的參数必须相应,这两个參数在AsyncTask声明的泛型參数列表中指定,第一个为doInBackground 接 受的參数。第二个为显示运行进度的參数。第第三个为doInBackground返回和onPostExecute传入的參数。

以上四点是我从网摘过来的。我认为说的有道理,针对第4点。我有异议:即使多次调用,也不应该出现异常,由于AsyncTask类有对外公开的接口,cancel(true),isCancelled()。这两个方法,这两个方法配合使用就来控制AsyncTask能够手动退出。

具体能够參照AsyncTask.java这个源代码类中有样例的。

  1. AsyncTask must be subclassed to be used. The subclass will override at least
  2. * one method ({@link #doInBackground}), and most often will override a
  3. * second one ({@link #onPostExecute}.)</p>
  4. *
  5. * <p>Here is an example of subclassing:</p>
  6. * <pre class="prettyprint">
  7. * private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
  8. * protected Long doInBackground(URL... urls) {
  9. * int count = urls.length;
  10. * long totalSize = 0;
  11. * for (int i = 0; i < count; i++) {
  12. * totalSize += Downloader.downloadFile(urls[i]);
  13. * publishProgress((int) ((i / (float) count) * 100));
  14. * // Escape early if cancel() is called
  15. * if (isCancelled()) break;
  16. * }
  17. * return totalSize;
  18. * }
  19. *
  20. * protected void onProgressUpdate(Integer... progress) {
  21. * setProgressPercent(progress[0]);
  22. * }
  23. *
  24. * protected void onPostExecute(Long result) {
  25. * showDialog("Downloaded " + result + " bytes");
  26. * }
  27. * }

这个是AsyncTask中给出的demo,看到

  1. if (isCancelled()) break;

这个就是用来推断是否退出后台线程。假设设置了cancel(true),就break跳出循环。

在这个地方多说2点:

(1)终止线程最好不要用打断线程来做,这种方式太粗暴了。并且不能保证代码的完整性,最好的处理方式就是在for循环。while循环中增加自己的推断标志位,就像AsyncTask这个方案来处理是最好的。这也是谷歌来指导我们怎么来处理终止线程的办法。

(2)也有同学感到疑惑,说我的代码就没有循环,怎么来加标志位,事实上这个一般来说后台处理,大部分都是处理循环的逻辑。非常少说一行代码或者十几行代码非常耗时的,(当然网络相关的另说了,还有下载相关的,这个有其它方法来解决的)。

即使有的话,比方调用jni,so库,返回就是慢。那就在几个耗时的方法的后面都加上标志位的推断。

通过上述方法就能够做出完整的方案设计,就能设计,当下次再次运行AsyncTask。先推断自己是否正在运行。假设在运行。就不运行或取消任务又一次运行,这个要看具体的需求是什么了;

举个栗子:

  1. private void stopAyncTaskRunning() {
  2. if (mContactsListLoader != null
  3. && mContactsListLoader.getStatus() == AsyncTask.Status.RUNNING) {
  4. mContactsListLoader.cancel(true); //if task is still running, stop it;
  5. }
  6.  
  7. }

  1. private void getContactsList() {
  2. stopAyncTaskRunning();
  3. mContactsListLoader = new ContactsListLoader();
  4. mContactsListLoader.executeOnExecutor(AsyncTask.THEAD_POOL_EXECUTOR);
  5. }

当然,我的这个需求是下次进来的时候,就取消上次的任务,然后又一次刷新数据。另外也不要忘记在doInBackground()中的循环语句中增加

  1. @Override
  2. protected Integer doInBackground(Object... arg0) {
  3.  
  4. List<Contact> contacts = new ArrayList<Contact>();
  5. ContentResolver cr = mContext.getContentResolver();
  6. Cursor c = cr.query(ContactsContract.Contacts.CONTENT_URI,
  7. PROJECTION_CONTACT, null, null, null);
  8. if (c != null) {
  9. c.moveToPosition(-1);
  10. while (c.moveToNext()) {
  11. if (isCancelled()) {
  12. break;
  13. }
  14.  
  15. 。。
  16.  
  17.  
  18. 。。
  19. }

这样,逻辑依照需求来写,需求是什么样子的,逻辑就相应的怎么处理;

再来说说AsyncTask坑人的地方,就是在Android3.0以后的版本号。AsyncTask的运行方法分为2个了:

(1)execute()
    (2)executeOnExecutor()

假设用AsyncTask调用(1)的时候,就表示串行运行线程,假设这个Activity中有4个fragment,并且每一个fragment都有一个AsyncTask,这种话用(1)的话,就必须顺序运行,等一个运行完,第二个才运行。假设用方法(2),则能够串行运行。这个UI效果就非常好了。线程池能够用系统的。也能够用我们自己定义的线程池;

另外对系统默认线程池中运行线程数的一些说明,例如以下:

以下的5代表corePoolSize,10代表堵塞队列的长度。128代表maximumPoolSize
1:假设线程池的数量小于5,则创建新的线程并运行
2:假设线程数大于5且小于5+10(堵塞队列大小)。则将第6~15的线程增加堵塞队列,待线程池中的5个正在运行的线程有某个结束后,取出堵塞队列的线程运行。
3:假设线程数为16~128,则运行的线程数为num-10
4:假设线程数大于128,则舍弃。

具体的的介绍能够參考博客:Android实战技巧:深入解析AsyncTask,这篇解说的非常具体;

   

   最后要说明的就是数据要载入一部分就刷新UI,给用户一个好的用户体验。举个栗子,

  1. private static final int DISPLAY_NUM = 10;
  2. private List<Contact> mContacts = new ArrayList<Contact>();
  3.  
  4. private class ContactsListLoader extends
  5. AsyncTask<Object, Integer, Integer> {
  6.  
  7. int count = 0;
  8. List<Contact> mTempContacts = new ArrayList<Contact>(DISPLAY_NUM);
  9.  
  10. @Override
  11. protected void onPreExecute() {
  12. super.onPreExecute();
  13. mTempContacts.clear();
  14. mContacts.clear();
  15. }
  16.  
  17. @Override
  18. protected Integer doInBackground(Object... arg0) {
  19.  
  20. List<Contact> contacts = new ArrayList<Contact>();
  21. if (c != null) {
  22. c.moveToPosition(-1);
  23. while (c.moveToNext()) {
  24. if (isCancelled()) {
  25. break;
  26. }
  27. ... ...
  28.  
  29. contacts.add(contact);
  30. mTempContacts.add(contact);
  31. if (++count >= DISPLAY_NUM) {
  32. publishProgress();
  33. count = 0;
  34. }
  35. }
  36. }
  37. return contacts.size();
  38. }
  39.  
  40. @Override
  41. protected void onProgressUpdate(Integer... values) {
  42. super.onProgressUpdate(values);
  43. mContacts.addAll(mTempContacts);
  44. mTempContacts.clear();
  45. mAdapter.notifyDataSetChanged();
  46. }
  47.  
  48. @Override
  49. protected void onPostExecute(Integer size) {
  50. if (isCancelled())
  51. return;
  52. if (size > 0) {
  53. if (mTempContacts.size() > 0
  54. && mTempContacts.size() != DISPLAY_NUM) {
  55. mContacts.addAll(mTempContacts);
  56. }
  57. } else {
  58. if (mTempContacts.size() > 0) {
  59. mContacts.addAll(mTempContacts);
  60. }
  61. }
  62. mAdapter.notifyDataSetChanged();
  63. }
  64.  
  65. }

这个就是我的模型,大家看懂后。就能够套到自己的代码中去了。这是我用来动态载入刷新UI的逻辑,刷新出10个数据就刷新一次,这样就能够避免次次刷新影响效率,又能保证用户不必等到数据都载入完才干看到数据。一举两得。

要想了解很多其它AsyncTask,能够參考源代码。假设有人了解的更深入,欢迎童鞋拍砖留言;

Android异步载入AsyncTask具体解释的更多相关文章

  1. Android异步载入全解析之使用AsyncTask

    Android异步载入全解析之使用AsyncTask 概述 既然前面提到了多线程,就不得不提到线程池,通过线程池,不仅能够对并发线程进行管理.更能够提高他们运行的效率.优化整个App.当然我们能够自己 ...

  2. Android异步载入全解析之IntentService

    Android异步载入全解析之IntentService 搞什么IntentService 前面我们说了那么多,异步处理都使用钦定的AsyncTask.再不济也使用的Thread,那么这个Intent ...

  3. Android异步载入全解析之大图处理

    Android异步载入全解析之大图处理 异步载入中很重要的一部分就是对图像的处理,这也是我们前面用异步载入图像做示例的原因. 一方面是由于图像处理不好的话会很占内存,并且easyOOM,还有一方面,图 ...

  4. Android异步载入全解析之使用多线程

    异步载入之使用多线程 初次尝试 异步.异步,事实上说白了就是多任务处理.也就是多线程执行.多线程那就会有各种问题,我们一步步来看.首先.我们创建一个class--ImageLoaderWithoutC ...

  5. Android异步载入全解析之开篇瞎扯淡

    Android异步载入 概述 Android异步载入在Android中使用的很广泛,除了是由于避免在主线程中做网络操作.更是为了避免在显示时由于时间太长而造成ANR,添加显示的流畅性,特别是像List ...

  6. Android备注26.Android异步任务(AsyncTask)

    转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.引言     我们知道Android的UI线程主要负责处理用户的按键事件.用户触屏事件及屏幕画 ...

  7. Android异步任务AsyncTask

    package com.example.asynctask; import java.net.MalformedURLException; import java.net.URL; import an ...

  8. Android异步载入学习笔记之四:利用缓存优化网络载入图片及ListView载入优化

    假设不做不论什么处理.直接用网络载入图片在网速快的情况下可能没什么不好的感觉.可是假设使用移动流量或是网络不好的时候.问题就来了,要么用户会抱怨流量使用太多.要么抱怨图片载入太慢.如论从哪个角度出发, ...

  9. Android 异步任务——AsyncTask (附使用AsyncTask下载图片Demo)

    我们编程的时候经常需要处理同步任务和异步任务,在Android里面存在一个特性,就是UI线程是不安全的线程.所谓UI线程不安全也就是我们的主线程(进程启动的第一个线程)不能在线程外操作主线程的资源.因 ...

随机推荐

  1. Github与Eclipse连接(方法2成功:Pleiades)

    2018-3-7 第1次尝试 主要参考这位大神的笔记:http://blog.csdn.net/zhangdaiscott/article/details/16939165 方法非常简单,从官网htt ...

  2. angular关于依赖注入

    <html> <head> <title>Angular JS Forms</title> </head> <body> < ...

  3. PHP文件函数

    PHP文件函数 函数 描述 PHPbasename() 返回路径中的文件名部分. 3chgrp() 改变文件组. 3chmod() 改变文件模式. 3chown() 改变文件所有者. 3clearst ...

  4. html css的简单学习(二)

    html css的简单学习(二) <!Doctype html>告诉浏览器,这是一个html文档.lang="en" 默认是en,表示英语:zh-Hans 中文简体:z ...

  5. Codeforces 404E: Maze 1D(二分)

    题意:指令“R”机器人会向右走一步,“L”是向左.起初机器人在0位置,可以在除了0以外的任何位置放障碍,如果机器人的指令将使它走到障碍上,那这一步他会保持不动.要求让机器人最终结束的那一步一定只走过一 ...

  6. asp传递参数的几种方式

    把下列代码分别加入a.asp和b.asp的<body></body>中,点提交,就可以将a.asp文本框的内容传给b.asp并显示出来 a.ASP <form actio ...

  7. SPOJ LIS2 - Another Longest Increasing Subsequence Problem(CDQ分治优化DP)

    题目链接  LIS2 经典的三维偏序问题. 考虑$cdq$分治. 不过这题的顺序应该是 $cdq(l, mid)$ $solve(l, r)$ $cdq(mid+1, r)$ 因为有个$DP$. #i ...

  8. [Python Cookbook] Numpy Array Manipulation

    1. Reshape: The np.reshape() method will give a new shape to an array without changing its data. Not ...

  9. 快速掌握RabbitMQ(五)——搭建高可用的RabbitMQ集群

    RabbitMQ的集群是依赖erlang集群的,而erlang集群是通过.erlang.cookie文件进行通信认证的,所以我们使用RabbitMQ集群时只需要配置一下.erlang.cookie文件 ...

  10. 邁向IT專家成功之路的三十則鐵律 鐵律二十九 IT人富足之道-信仰

    天地自然的循環法則,讓每一個人都必須經歷生.老.病.死.喜.怒.哀.樂,然而至始至終無盡的煩惱總是遠多於快樂,因此筆者深信每一個人在一生當中,都必須要有適合自己的正確信仰,他可以在你無法以物質力量來解 ...