Android多线程任务的优化1:AsyncTask的缺陷 (转至 http://www.linuxidc.com/Linux/2011-09/43150.htm)
导语:在开发Android应用的过程中,我们需要时刻注意保障应用的稳定性和界面响应性,因为不稳定或者响应速度慢的应用将会给用户带来非常差的交互体验。在越来越讲究用户体验的大环境下,用户也许会因为应用的一次Force Close(简称FC)或者延迟严重的动画效果而卸载你的应用。由于现在的应用大多需要异步连接网络,本系列文章就以构建网络应用为例,从稳定性和响应性两个角度分析多线程网络任务的性能优化方法。
概述:为了不阻塞UI线程(亦称主线程),提高应用的响应性,我们经常会使用新开线程的方式,异步处理那些导致阻塞的任务(如要了解Android异步处理的实现方式和原理,请先阅读《Android异步处理系列文章索引》)。
AsyncTask是Android为我们提供的方便编写异步任务的工具类,但是,在了解AsyncTask的实现原理之后,发现AsyncTask并不能满足我们所有的需求,使用不当还有可能导致应用FC。
本文主要通过分析AsyncTask提交任务的策略和一个具体的例子,说明AsyncTask的不足之处,至于解决办法,我们将在下篇再讲解。
分析:
AsyncTask类包含一个全局静态的线程池,线程池的配置参数如下:
- ;//5个核心工作线程
- ;//最多128个工作线程
- ;//空闲线程的超时时间为1秒
- private static final BlockingQueue<Runnable> sWorkQueue =
- );//等待队列
- private static final ThreadPoolExecutorsExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
- 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
- package com.zhuozhuo;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.ListIterator;
- import java.util.Map;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.app.Dialog;
- import android.app.ListActivity;
- import android.app.ProgressDialog;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.database.Cursor;
- import android.graphics.Bitmap;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.provider.ContactsContract;
- import android.util.Log;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.AbsListView;
- import android.widget.AbsListView.OnScrollListener;
- import android.widget.Adapter;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.BaseAdapter;
- import android.widget.GridView;
- import android.widget.ImageView;
- import android.widget.ListAdapter;
- import android.widget.SimpleAdapter;
- import android.widget.TextView;
- import android.widget.Toast;
- public class ActivityA extends Activity {
- private GridView mGridView;
- private List<HashMap<String, Object>> mData;
- private BaseAdapter mAdapter;
- private ProgressDialog mProgressDialog;
- ;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mGridView = (GridView) findViewById(R.id.gridview);
- mData = new ArrayList<HashMap<String,Object>>();
- mAdapter = new CustomAdapter();
- mGridView.setAdapter(mAdapter);
- }
- protected void onStart () {
- super.onStart();
- new GetGridDataTask().execute(null);//执行获取数据的任务
- }
- @Override
- protected Dialog onCreateDialog(int id) {
- switch (id) {
- case DIALOG_PROGRESS:
- mProgressDialog = new ProgressDialog(ActivityA.this);
- mProgressDialog.setMessage("正在获取数据");
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
- return mProgressDialog;
- }
- return null;
- }
- class CustomAdapter extends BaseAdapter {
- CustomAdapter() {
- }
- @Override
- public int getCount() {
- return mData.size();
- }
- @Override
- public Object getItem(int position) {
- return mData.get(position);
- }
- @Override
- public long getItemId(int position) {
- ;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View view = convertView;
- ViewHolder vh;
- if(view == null) {
- view = LayoutInflater.from(ActivityA.this).inflate(R.layout.list_item, null);
- vh = new ViewHolder();
- vh.tv = (TextView) view.findViewById(R.id.textView);
- vh.iv = (ImageView) view.findViewById(R.id.imageView);
- view.setTag(vh);
- }
- vh = (ViewHolder) view.getTag();
- vh.tv.setText((String) mData.get(position).get("title"));
- Integer id = (Integer) mData.get(position).get("pic");
- if(id != null) {
- vh.iv.setImageResource(id);
- }
- else {
- vh.iv.setImageBitmap(null);
- }
- FifoAsyncTask task = (FifoAsyncTask) mData.get(position).get("task");
- if(task == null || task.isCancelled()) {
- Log.d("Test", "" + position);
- mData.get(position).put("task", new GetItemImageTask(position).execute(null));//执行获取图片的任务
- }
- return view;
- }
- }
- static class ViewHolder {
- TextView tv;
- ImageView iv;
- }
- class GetGridDataTask extends FifoAsyncTask<Void, Void, Void> {
- protected void onPreExecute () {
- mData.clear();
- mAdapter.notifyDataSetChanged();
- showDialog(DIALOG_PROGRESS);//打开等待对话框
- }
- @Override
- protected Void doInBackground(Void... params) {
- try {
- Thread.sleep();//模拟耗时的网络操作
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- ; i < ; i++) {
- HashMap<String, Object> hm = new HashMap<String, Object>();
- hm.put("title", "Title");
- mData.add(hm);
- }
- return null;
- }
- protected void onPostExecute (Void result) {
- mAdapter.notifyDataSetChanged();//通知ui界面更新
- dismissDialog(DIALOG_PROGRESS);//关闭等待对话框
- }
- }
- class GetItemImageTask extends FifoAsyncTask<Void, Void, Void> {
- int pos;
- GetItemImageTask(int pos) {
- this.pos = pos;
- }
- @Override
- protected Void doInBackground(Void... params) {
- try {
- Thread.sleep(); //模拟耗时的网络操作
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- mData.get(pos).put("pic", R.drawable.icon);
- return null;
- }
- protected void onPostExecute (Void result) {
- mAdapter.notifyDataSetChanged();//通知ui界面更新
- }
- }
- }

由运行图可见
当网络情况较差,异步任务不能尽快完成执行的情况下,新开的线程会造成listview滑动不流畅。当开启的工作线程过多时,还有出现FC的可能。
至此,你还相信万能��AsyncTask吗?至于你信不信,反正我不信。
总结:
AsyncTask可能存在新开大量线程消耗系统资源和导致应用FC的风险,因此,我们需要根据自己的需求自定义不同的线程池,由于篇幅问题,将留到下篇再讲。
Android多线程任务的优化1:AsyncTask的缺陷 (转至 http://www.linuxidc.com/Linux/2011-09/43150.htm)的更多相关文章
- Android多线程分析之五:使用AsyncTask异步下载图像
Android多线程分析之五:使用AsyncTask异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 在本系列文章的第一篇<An ...
- Android多线程任务优化1:探讨AsyncTask的缺陷
AsyncTask还有别的缺陷,在生成listview的时候,如果adapter里面的count动态改变的话,不能使用AsyncTask,只能使用Thread+Handler,否则会出现如下错误 j ...
- android多线程-AsyncTask之工作原理深入解析(下)
关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...
- android多线程-AsyncTask之工作原理深入解析(上)
关联文章: Android 多线程之HandlerThread 完全详解 Android 多线程之IntentService 完全详解 android多线程-AsyncTask之工作原理深入解析(上) ...
- 转 Android 多线程:手把手教你使用AsyncTask
转自:https://www.jianshu.com/p/ee1342fcf5e7 前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 继承Thread类 实现Runnable接口 ...
- android 多线程
本章讲述在android开发中,多线程的应用.多线程能够处理耗时的操作并优化程序的性能.本章主要介绍知识点,AsyncTask,Java线程池,ThreadPoolExecutor线程池类.本章案例只 ...
- Android多线程分析之四:MessageQueue的实现
Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...
- 关于android应用--内存的优化
以下内容为转载自网上,然后自己加工贴合到一块的: 原文地址:http://www.cnblogs.com/frydsh/archive/2012/12/09/2810601.html http://w ...
- Android中使用Thread线程与AsyncTask异步任务的区别
最近和几个朋友交流Android开发中的网络下载问题时,谈到了用Thread开启下载线程时会产生的Bug,其实直接用子线程开启下载任务的确是很Low的做法,那么原因究竟如何,而比较高大上的做法是怎样? ...
随机推荐
- cocos2d-x开发记录:二,基本概念(导演,场景,层和精灵,场景切换,效果)
四,Director Scene Layer和Sprite(导演,场景,层和精灵) 1.Scenes(场景) 一个场景 (用CCScene对象实现)相当于APP工作流的独立部分.一些人也喜欢叫做“屏幕 ...
- sqlite数据库部署到服务器上的问题
试了一天...本地测试是好的(WIN10 64位+VS2015),部署到服务器上(WIN2008 32位+IIS6) 总是不行..按网上说了什么不要BUNDLE的,加入X86X64目录再放那个SQLi ...
- linux安装rzsz(lrzsz)
lrzsz是一个unix通信套件提供的,X,Y和ZModem文件传输协议,可以用在Windows与linux系统之间的文件传输,体积小速度快,可以与xshell工具配合使用. (1)在线安装 yum ...
- http请求头中的Content-Type属性在angular 和 node中的用法
post请求的请求体有以下两种格式: 1. 字符串: 'name=code_bunny&age=12' 这种格式的请求体,需要配置请求头 'Content-Type':'application ...
- angular学习笔记(二)-创建angular模块
如果在页面的html标签(或任意标签)中添加ng-app,表示对整个页面应用angular来管理. 他是一个模块. 模块有助于把东西从全局命名空间中隔离. 今天学习如何自定义创建模块: <!DO ...
- 编译是报error: 'EVNET_COME_TO_FOREGROUND' was not declared in this scope
Compile++ thumb : game_shared <= main.cpp jni/hellocpp/main.cpp: In function 'void Java_org_coco ...
- ny520 最大素因子 筛选法求素数
最大素因子时间限制:1000 ms | 内存限制:65535 KB难度:2 描述 GreyAnts最近正在学习数论中的素数,但是现在他遇到了一个难题:给定一个整数n,要求我们求出n的最大素因子的序 ...
- linux 双显卡问题。。。
bumblebee的作用是禁用nvidia独立显卡,需要使用独显时,使用”optirun 程序名“手动开启nvidia来运行需要加速的程序,如optirun vmware. 打开N卡设置: optir ...
- singer页左侧滚动的时候右侧跟随高亮显示
1.封装scroll.vue的listenScroll属性和方法,用来确定监听listview.vue的滚动事件 2.将listview.vue的listenScroll属性默认设置为true; 3. ...
- 【Unity笔记】UGUI的自动布局功能
一些RectTransform的物体(UGUI元素)已经实现了ILayoutElement接口,如Image. 如果一个RectTransform的物体(UGUI元素)的其中一个组件实现了ILayou ...