当前位置: 代码迷 >> Android >> Android多线程任务优化一:探讨AsyncTask的缺陷(转)
  详细解决方案

Android多线程任务优化一:探讨AsyncTask的缺陷(转)

热度:71   发布时间:2016-05-01 10:30:12.0
Android多线程任务优化1:探讨AsyncTask的缺陷(转)

转自:?http://blog.csdn.net/mylzc/article/details/6784415

?

导语:在开发Android应用的过程中,我们需要时刻注意保障应用的稳定性和界面响应性,因为不稳定或者响应速度慢的应用将会给用户带来非常差的交互体验。在越来越讲究用户体验的大环境下,用户也许会因为应用的一次Force Close(简称FC)或者延迟严重的动画效果而卸载你的应用。由于现在的应用大多需要异步连接网络,本系列文章就以构建网络应用为例,从稳定性和响应性两个角度分析多线程网络任务的性能优化方法。

概述:为了不阻塞UI线程(亦称主线程),提高应用的响应性,我们经常会使用新开线程的方式,异步处理那些导致阻塞的任务(如要了解Android异步处理的实现方式和原理,请先阅读《Android异步处理系列文章索引》)。

AsyncTask是Android为我们提供的方便编写异步任务的工具类,但是,在了解AsyncTask的实现原理之后,发现AsyncTask并不能满足我们所有的需求,使用不当还有可能导致应用FC。

本文主要通过分析AsyncTask提交任务的策略和一个具体的例子,说明AsyncTask的不足之处,至于解决办法,我们将在下篇再讲解。

分析

AsyncTask类包含一个全局静态的线程池,线程池的配置参数如下:

?

[java]?view plaincopy
?
  1. private?static?final?int?CORE_POOL_SIZE?=5;//5个核心工作线程??
  2. ???private?static?final?int?MAXIMUM_POOL_SIZE?=?128;//最多128个工作线程??
  3. ???private?static?final?int?KEEP_ALIVE?=?1;//空闲线程的超时时间为1秒??
  4. ???
  5. ???private?static?final?BlockingQueue<Runnable>?sWorkQueue?=??
  6. ???????????new?LinkedBlockingQueue<Runnable>(10);//等待队列??
  7. ???
  8. ???private?static?final?ThreadPoolExecutorsExecutor?=?new?ThreadPoolExecutor(CORE_POOL_SIZE,??
  9. ???????????MAXIMUM_POOL_SIZE,?KEEP_ALIVE,?TimeUnit.SECONDS,?sWorkQueue,sThreadFactory);//线程池是静态变量,所有的异步任务都会放到这个线程池的工作线程内执行。??



?

我们这里不详细讲解ThreadPoolExecutor的原理,但将会讲解一个异步任务提交到AsyncTask的线程池时可能会出现的4种情况,并会提出在Android硬件配置普遍较低这个客观条件下,每个情况可能会出现的问题。

1、线程池中的工作线程少于5个时,将会创建新的工作线程执行异步任务(红色表示新任务,下同)

2、线程池中已经有5个线程,缓冲队列未满,异步任务将会放到缓冲队列中等待

3、线程池中已经有5个线程,缓冲队列已满,那么线程池将新开工作线程执行异步任务

问题:Android的设备一般不超过2个cpu核心,过多的线程会造成线程间切换频繁,消耗系统资源。

4、线程池中已经有128个线程,缓冲队列已满,如果此时向线程提交任务,将会抛出RejectedExecutionException

问题:抛出的错误不catch的话会导致程序FC。

?

好吧,理论分析之后还是要结合实际例子,我们通过实现一个模拟异步获取网络图片的例子,看看会不会出现上面提到的问题。

?

例子:使用GridView模拟异步加载大量图片

ActivityA.java

?

[java]?view plaincopy
?
  1. package?com.zhuozhuo;??
  2. ??
  3. import?java.util.ArrayList;??
  4. import?java.util.Collection;??
  5. import?java.util.HashMap;??
  6. import?java.util.Iterator;??
  7. import?java.util.List;??
  8. import?java.util.ListIterator;??
  9. import?java.util.Map;??
  10. ??
  11. ??
  12. import?android.app.Activity;??
  13. import?android.app.AlertDialog;??
  14. import?android.app.Dialog;??
  15. import?android.app.ListActivity;??
  16. import?android.app.ProgressDialog;??
  17. import?android.content.Context;??
  18. import?android.content.DialogInterface;??
  19. import?android.content.Intent;??
  20. import?android.database.Cursor;??
  21. import?android.graphics.Bitmap;??
  22. import?android.os.AsyncTask;??
  23. import?android.os.Bundle;??
  24. import?android.provider.ContactsContract;??
  25. import?android.util.Log;??
  26. import?android.view.LayoutInflater;??
  27. import?android.view.View;??
  28. import?android.view.ViewGroup;??
  29. import?android.widget.AbsListView;??
  30. import?android.widget.AbsListView.OnScrollListener;??
  31. import?android.widget.Adapter;??
  32. import?android.widget.AdapterView;??
  33. import?android.widget.AdapterView.OnItemClickListener;??
  34. import?android.widget.BaseAdapter;??
  35. import?android.widget.GridView;??
  36. import?android.widget.ImageView;??
  37. import?android.widget.ListAdapter;??
  38. import?android.widget.SimpleAdapter;??
  39. import?android.widget.TextView;??
  40. import?android.widget.Toast;??
  41. ??
  42. public?class?ActivityA?extends?Activity?{??
  43. ??????
  44. ??????
  45. ????private?GridView?mGridView;??
  46. ????private?List<HashMap<String,?Object>>?mData;??
  47. ??????
  48. ????private?BaseAdapter?mAdapter;??
  49. ????private?ProgressDialog?mProgressDialog;??
  50. ??????
  51. ????private?static?final?int?DIALOG_PROGRESS?=?0;??
  52. ??????
  53. ????@Override??
  54. ????public?void?onCreate(Bundle?savedInstanceState)?{??
  55. ????????super.onCreate(savedInstanceState);??
  56. ????????setContentView(R.layout.main);??
  57. ????????mGridView?=?(GridView)?findViewById(R.id.gridview);??
  58. ????????mData?=?new?ArrayList<HashMap<String,Object>>();??
  59. ????????mAdapter?=?new?CustomAdapter();??
  60. ??????????
  61. ?????????
  62. ????????mGridView.setAdapter(mAdapter);??
  63. ????}??
  64. ??????
  65. ????protected?void?onStart?()?{??
  66. ????????super.onStart();??
  67. ????????new?GetGridDataTask().execute(null);//执行获取数据的任务??
  68. ????}??
  69. ??????
  70. ??????
  71. ??????
  72. ??????
  73. ????@Override??
  74. ????protected?Dialog?onCreateDialog(int?id)?{??
  75. ????????switch?(id)?{??
  76. ????????case?DIALOG_PROGRESS:??
  77. ????????????mProgressDialog?=?new?ProgressDialog(ActivityA.this);??
  78. ????????????mProgressDialog.setMessage("正在获取数据");??
  79. ????????????mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);??
  80. ??
  81. ????????????return?mProgressDialog;??
  82. ??
  83. ?????????
  84. ????????}??
  85. ????????return?null;??
  86. ????}??
  87. ??
  88. ????class?CustomAdapter?extends?BaseAdapter?{??
  89. ??
  90. ??????????
  91. ????????CustomAdapter()?{??
  92. ??????????????
  93. ????????}??
  94. ??????????
  95. ????????@Override??
  96. ????????public?int?getCount()?{??
  97. ????????????return?mData.size();??
  98. ????????}??
  99. ??
  100. ????????@Override??
  101. ????????public?Object?getItem(int?position)?{??
  102. ????????????return?mData.get(position);??
  103. ????????}??
  104. ??
  105. ????????@Override??
  106. ????????public?long?getItemId(int?position)?{??
  107. ????????????return?0;??
  108. ????????}??
  109. ??
  110. ????????@Override??
  111. ????????public?View?getView(int?position,?View?convertView,?ViewGroup?parent)?{??
  112. ????????????View?view?=?convertView;??
  113. ????????????ViewHolder?vh;??
  114. ????????????if(view?==?null)?{??
  115. ????????????????view?=?LayoutInflater.from(ActivityA.this).inflate(R.layout.list_item,?null);??
  116. ????????????????vh?=?new?ViewHolder();??
  117. ????????????????vh.tv?=?(TextView)?view.findViewById(R.id.textView);??
  118. ????????????????vh.iv?=?(ImageView)?view.findViewById(R.id.imageView);??
  119. ????????????????view.setTag(vh);??
  120. ????????????}??
  121. ????????????vh?=?(ViewHolder)?view.getTag();??
  122. ????????????vh.tv.setText((String)?mData.get(position).get("title"));??
  123. ????????????Integer?id?=?(Integer)?mData.get(position).get("pic");??
  124. ????????????if(id?!=?null)?{??
  125. ????????????????vh.iv.setImageResource(id);??
  126. ????????????}??
  127. ????????????else?{??
  128. ????????????????vh.iv.setImageBitmap(null);??
  129. ????????????}??
  130. ??????????????
  131. ????????????FifoAsyncTask?task?=?(FifoAsyncTask)?mData.get(position).get("task");??
  132. ????????????if(task?==?null?||?task.isCancelled())?{??
  133. ????????????????Log.d("Test",?""?+?position);??
  134. ????????????????mData.get(position).put("task",?new?GetItemImageTask(position).execute(null));//执行获取图片的任务??
  135. ????????????}??
  136. ??????????????
  137. ????????????return?view;??
  138. ????????}??
  139. ??
  140. ??????????
  141. ??????????
  142. ????}??
  143. ??????
  144. ????static?class?ViewHolder?{??
  145. ????????TextView?tv;??
  146. ????????ImageView?iv;??
  147. ????}??
  148. ??????
  149. ????class?GetGridDataTask?extends?FifoAsyncTask<Void,?Void,?Void>?{??
  150. ??????????
  151. ????????protected?void?onPreExecute?()?{??
  152. ????????????mData.clear();??
  153. ????????????mAdapter.notifyDataSetChanged();??
  154. ??????????????
  155. ????????????showDialog(DIALOG_PROGRESS);//打开等待对话框??
  156. ????????}??
  157. ??????????
  158. ????????@Override??
  159. ????????protected?Void?doInBackground(Void...?params)?{??
  160. ??????????????
  161. ????????????try?{??
  162. ????????????????Thread.sleep(500);//模拟耗时的网络操作??
  163. ????????????}?catch?(InterruptedException?e)?{??
  164. ????????????????e.printStackTrace();??
  165. ????????????}??
  166. ????????????for(int?i?=?0;?i?<?200;?i++)?{??
  167. ????????????????HashMap<String,?Object>?hm?=?new?HashMap<String,?Object>();??
  168. ????????????????hm.put("title",?"Title");??
  169. ????????????????mData.add(hm);??
  170. ????????????}??
  171. ??????????????
  172. ????????????return?null;??
  173. ????????}??
  174. ??????????
  175. ????????protected?void?onPostExecute?(Void?result)?{??
  176. ????????????mAdapter.notifyDataSetChanged();//通知ui界面更新??
  177. ????????????dismissDialog(DIALOG_PROGRESS);//关闭等待对话框??
  178. ????????}??
  179. ??????????
  180. ????}??
  181. ??????
  182. ????class?GetItemImageTask?extends?FifoAsyncTask<Void,?Void,?Void>?{??
  183. ??????????
  184. ????????int?pos;??
  185. ??????????
  186. ????????GetItemImageTask(int?pos)?{??
  187. ????????????this.pos?=?pos;??
  188. ????????}??
  189. ??
  190. ????????@Override??
  191. ????????protected?Void?doInBackground(Void...?params)?{??
  192. ????????????try?{??
  193. ????????????????Thread.sleep(2000);?//模拟耗时的网络操作??
  194. ????????????}?catch?(InterruptedException?e)?{??
  195. ????????????????e.printStackTrace();??
  196. ????????????}??
  197. ????????????mData.get(pos).put("pic",?R.drawable.icon);??
  198. ????????????return?null;??
  199. ????????}??
  200. ??????????
  201. ????????protected?void?onPostExecute?(Void?result)?{??
  202. ????????????mAdapter.notifyDataSetChanged();//通知ui界面更新??
  203. ????????}??
  204. ??????????
  205. ????}??
  206. ??
  207. }??



?

?

?

由运行图可见

当网络情况较差,异步任务不能尽快完成执行的情况下,新开的线程会造成listview滑动不流畅。当开启的工作线程过多时,还有出现FC的可能。

至此,你还相信万能的AsyncTask吗?至于你信不信,反正我不信。

总结:

AsyncTask可能存在新开大量线程消耗系统资源和导致应用FC的风险,因此,我们需要根据自己的需求自定义不同的线程池,由于篇幅问题,将留到下篇再讲。

  相关解决方案