Android_AsyncTask详解及其应用(二 )_RejectedExecutionException问题
2013-10-16 17:50
627 查看
http://blog.csdn.net/wangjinyu501/article/details/9008219
在这篇文章里面说了AsyncTask的基本用法,想要进一步了解它是如何运行的朋友可以看一下这篇文章:点击,里面详细介绍了AsyncTask的原理以及运行流程。之前只是使用AsyncTask下载一张图片,显然在一个应用中不太现实,如果是很多图片,那使用AsyncTask会不会出现问题呢?下面来试一下,让ListView显示多张图片,使用AsyncTask下载图片。
代码如下:
[java] view
plaincopy
package com.example.asynctaskdemo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
public class Asy4Activity extends Activity {
private ListView listview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handlerimageloader);
listview = (ListView) findViewById(R.id.listview);
listview.setAdapter(new MyAdapter());
}
private class MyAdapter extends BaseAdapter {
public MyAdapter() {
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return 100;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getApplicationContext())
.inflate(R.layout.list_item, null);
}
final ImageView image = (ImageView) convertView
.findViewById(R.id.imageview);
String imageURL = "http://images.ladymax.cn/userup/1305/29111RO915.jpg";
class AsyncTaskLoadImage extends AsyncTask<String, Integer, Bitmap> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
try {
URL url = new URL(params[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.connect();
int MAX = urlConnection.getContentLength();
InputStream inputStream = urlConnection
.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = inputStream.read(b)) != -1) {
byteArrayOutputStream.write(b, 0, len);
}
bitmap = BitmapFactory.decodeByteArray(
byteArrayOutputStream.toByteArray(), 0, MAX);
inputStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
image.setImageBitmap(result);
}
}
AsyncTaskLoadImage asyncTaskLoadImage = new AsyncTaskLoadImage();
asyncTaskLoadImage.execute(imageURL);
return convertView;
}
}
}
在这里让ListView显示100张图片,如图:
出现了两个异常,一个是:
这个异常很常见,就是经常说的OOM,内存溢出了,原因也是因为代码里并没有做OOM问题的优化处理,比如使用缓存、分页加载、重用等等。再看一下第二个异常:
那这个错误是什么呢?其实原因是当运行的AsyncTask 实例数量过多的时候会引发RejectedExecutionException异常。例如网络情况较差时,有大量的线程在等待。那如何解决这个问题呢?
思路:
既然抛出了RejectedExecutionException这个异常,那就从它开始。翻看java的在线文档RejectedExecutionException,我们看到了这个错误的解释:
[java] view
plaincopy
public class RejectedExecutionException
extends RuntimeException
Exception thrown by an Executor when a task cannot be accepted for execution. Since:
1.5
See Also:
Serialized Form这个表明是Executor这个类不接受执行task时抛出的异常。而Executor是java1.5之后增加的java.util.concurrent包中操作多线程的主要类。可以执行多个RunnableTask,看来google的AsyncTask就是用的这套API。了解到这点,我们就可以打开AsyncTask的源码查看它到底是怎么实现的:打开源码之后,找到execute方法:
[java] view
plaincopy
1 /**
2 * Executes the task with the specified parameters. The task returns
3 * itself (this) so that the caller can keep a reference to it.
4 *
5 * This method must be invoked on the UI thread.
6 *
7 * @param params The parameters of the task.
8 *
9 * @return This instance of AsyncTask.
10 *
11 * @throws IllegalStateException If {@link #getStatus()} returns either
12 * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
13 */
14 public final AsyncTask<Params, Progress, Result> execute(Params... params) {
15 if (mStatus != Status.PENDING) {
16 switch (mStatus) {
17 case RUNNING:
18 throw new IllegalStateException("Cannot execute task:"
19 + " the task is already running.");
20 case FINISHED:
21 throw new IllegalStateException("Cannot execute task:"
22 + " the task has already been executed "
23 + "(a task can be executed only once)");
24 }
25 }
26
27 mStatus = Status.RUNNING;
28
29 onPreExecute();
30
31 mWorker.mParams = params;
32 sExecutor.execute(mFuture);
33
34 return this;
35 } 找到这里使用的Executor是sExecutor这个属性,这样来到它赋值的地方
[java] view
plaincopy
1 private static final String LOG_TAG = "AsyncTask";
2
3 private static final int CORE_POOL_SIZE = 5;
4 private static final int MAXIMUM_POOL_SIZE = 128;
5 private static final int KEEP_ALIVE = 10;
6
7 private static final BlockingQueue<Runnable> sWorkQueue =
8 new LinkedBlockingQueue<Runnable>(10);
9
10 private static final ThreadFactory sThreadFactory = new ThreadFactory() {
11 private final AtomicInteger mCount = new AtomicInteger(1);
12
13 public Thread newThread(Runnable r) {
14 return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
15 }
16 };
17
18 private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
19 MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);可以看到他是构造了一个ThreadPoolExecutor常量,保证new出多个AsyncTask都是使用这一个Executor。异常应该是它抛出的,我们看下这个类的文档,其中有一段是这样描述的:
Rejected tasks
New tasks submitted in method execute(Runnable) will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads
and work queue capacity, and is saturated. In either case, the execute method invokes the rejectedExecution(Runnable, ThreadPoolExecutor) method of its RejectedExecutionHandler. Four predefined handler policies are provided:
1.In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.
2.In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down
the rate that new tasks are submitted.
3.In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.
4.In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which
can fail again, causing this to be repeated.)
It is possible to define and use other kinds of RejectedExecutionHandler classes. Doing so requires some care especially when policies are designed to work only under particular
capacity or queuing policies. 原来在Executor的队列和容量都达到最大时,再次增加新的task的时候将会进行拒绝行为,而默认的拒绝行为就是抛出这个RejectedExecutionException异常。
那解决方案也就诞生了,就是复制一份AsyncTask的源码,自己重写这个初始化方法,增加相应的拒绝策略,后面就有几个可供选择的策略。修改AsyncTask源码如下
[java] view
plaincopy
1 private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
2 MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());再次运行,OK,不会再抛出那个异常了。
推荐博客: 1、Android AsyncTask behavior changes you should know
2、Android实战技巧:深入解析AsyncTask
3、AsyncTask 使用须知
4、Android多线程任务优化1:探讨AsyncTask的缺陷
5、解决java.util.concurrent.RejectedExecutionException问题
在这篇文章里面说了AsyncTask的基本用法,想要进一步了解它是如何运行的朋友可以看一下这篇文章:点击,里面详细介绍了AsyncTask的原理以及运行流程。之前只是使用AsyncTask下载一张图片,显然在一个应用中不太现实,如果是很多图片,那使用AsyncTask会不会出现问题呢?下面来试一下,让ListView显示多张图片,使用AsyncTask下载图片。
代码如下:
[java] view
plaincopy
package com.example.asynctaskdemo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
public class Asy4Activity extends Activity {
private ListView listview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handlerimageloader);
listview = (ListView) findViewById(R.id.listview);
listview.setAdapter(new MyAdapter());
}
private class MyAdapter extends BaseAdapter {
public MyAdapter() {
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return 100;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getApplicationContext())
.inflate(R.layout.list_item, null);
}
final ImageView image = (ImageView) convertView
.findViewById(R.id.imageview);
String imageURL = "http://images.ladymax.cn/userup/1305/29111RO915.jpg";
class AsyncTaskLoadImage extends AsyncTask<String, Integer, Bitmap> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap = null;
try {
URL url = new URL(params[0]);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.connect();
int MAX = urlConnection.getContentLength();
InputStream inputStream = urlConnection
.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = inputStream.read(b)) != -1) {
byteArrayOutputStream.write(b, 0, len);
}
bitmap = BitmapFactory.decodeByteArray(
byteArrayOutputStream.toByteArray(), 0, MAX);
inputStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
image.setImageBitmap(result);
}
}
AsyncTaskLoadImage asyncTaskLoadImage = new AsyncTaskLoadImage();
asyncTaskLoadImage.execute(imageURL);
return convertView;
}
}
}
在这里让ListView显示100张图片,如图:
出现了两个异常,一个是:
这个异常很常见,就是经常说的OOM,内存溢出了,原因也是因为代码里并没有做OOM问题的优化处理,比如使用缓存、分页加载、重用等等。再看一下第二个异常:
那这个错误是什么呢?其实原因是当运行的AsyncTask 实例数量过多的时候会引发RejectedExecutionException异常。例如网络情况较差时,有大量的线程在等待。那如何解决这个问题呢?
思路:
既然抛出了RejectedExecutionException这个异常,那就从它开始。翻看java的在线文档RejectedExecutionException,我们看到了这个错误的解释:
[java] view
plaincopy
public class RejectedExecutionException
extends RuntimeException
Exception thrown by an Executor when a task cannot be accepted for execution. Since:
1.5
See Also:
Serialized Form这个表明是Executor这个类不接受执行task时抛出的异常。而Executor是java1.5之后增加的java.util.concurrent包中操作多线程的主要类。可以执行多个RunnableTask,看来google的AsyncTask就是用的这套API。了解到这点,我们就可以打开AsyncTask的源码查看它到底是怎么实现的:打开源码之后,找到execute方法:
[java] view
plaincopy
1 /**
2 * Executes the task with the specified parameters. The task returns
3 * itself (this) so that the caller can keep a reference to it.
4 *
5 * This method must be invoked on the UI thread.
6 *
7 * @param params The parameters of the task.
8 *
9 * @return This instance of AsyncTask.
10 *
11 * @throws IllegalStateException If {@link #getStatus()} returns either
12 * {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
13 */
14 public final AsyncTask<Params, Progress, Result> execute(Params... params) {
15 if (mStatus != Status.PENDING) {
16 switch (mStatus) {
17 case RUNNING:
18 throw new IllegalStateException("Cannot execute task:"
19 + " the task is already running.");
20 case FINISHED:
21 throw new IllegalStateException("Cannot execute task:"
22 + " the task has already been executed "
23 + "(a task can be executed only once)");
24 }
25 }
26
27 mStatus = Status.RUNNING;
28
29 onPreExecute();
30
31 mWorker.mParams = params;
32 sExecutor.execute(mFuture);
33
34 return this;
35 } 找到这里使用的Executor是sExecutor这个属性,这样来到它赋值的地方
[java] view
plaincopy
1 private static final String LOG_TAG = "AsyncTask";
2
3 private static final int CORE_POOL_SIZE = 5;
4 private static final int MAXIMUM_POOL_SIZE = 128;
5 private static final int KEEP_ALIVE = 10;
6
7 private static final BlockingQueue<Runnable> sWorkQueue =
8 new LinkedBlockingQueue<Runnable>(10);
9
10 private static final ThreadFactory sThreadFactory = new ThreadFactory() {
11 private final AtomicInteger mCount = new AtomicInteger(1);
12
13 public Thread newThread(Runnable r) {
14 return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
15 }
16 };
17
18 private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
19 MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);可以看到他是构造了一个ThreadPoolExecutor常量,保证new出多个AsyncTask都是使用这一个Executor。异常应该是它抛出的,我们看下这个类的文档,其中有一段是这样描述的:
Rejected tasks
New tasks submitted in method execute(Runnable) will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads
and work queue capacity, and is saturated. In either case, the execute method invokes the rejectedExecution(Runnable, ThreadPoolExecutor) method of its RejectedExecutionHandler. Four predefined handler policies are provided:
1.In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.
2.In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down
the rate that new tasks are submitted.
3.In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.
4.In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which
can fail again, causing this to be repeated.)
It is possible to define and use other kinds of RejectedExecutionHandler classes. Doing so requires some care especially when policies are designed to work only under particular
capacity or queuing policies. 原来在Executor的队列和容量都达到最大时,再次增加新的task的时候将会进行拒绝行为,而默认的拒绝行为就是抛出这个RejectedExecutionException异常。
那解决方案也就诞生了,就是复制一份AsyncTask的源码,自己重写这个初始化方法,增加相应的拒绝策略,后面就有几个可供选择的策略。修改AsyncTask源码如下
[java] view
plaincopy
1 private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
2 MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory, new ThreadPoolExecutor.DiscardOldestPolicy());再次运行,OK,不会再抛出那个异常了。
推荐博客: 1、Android AsyncTask behavior changes you should know
2、Android实战技巧:深入解析AsyncTask
3、AsyncTask 使用须知
4、Android多线程任务优化1:探讨AsyncTask的缺陷
5、解决java.util.concurrent.RejectedExecutionException问题
相关文章推荐
- Android_AsyncTask详解及其应用(二 )_RejectedExecutionException问题
- Android_AsyncTask详解及其应用(三)_图片错位以及AsyncTask重复创建的问题
- Android_AsyncTask详解及其应用(三)_图片错位以及AsyncTask重复创建的问题
- Android_AsyncTask详解及其应用(三)_图片错位以及AsyncTask重复创建的问题
- Android_AsyncTask详解及其应用(一)
- Android_AsyncTask详解及其应用(一)
- Android_AsyncTask详解及其应用(一)
- 【Android 应用开发】Android屏幕适配解析 - 详解像素,设备独立像素,归一化密度,精确密度及各种资源对应的尺寸密度分辨率适配问题
- 【Android 应用开发】Android屏幕适配解析 - 详解像素,设备独立像素,归一化密度,精确密度及各种资源对应的尺寸密度分辨率适配问题
- Android pdf viewer在android studio应用问题说明详解
- android 获取imei(国际移动设备身份码)号码详解及其应用场景
- Android AsyncTask cannot resolve CalledFromWrongThreadException问题解决方案
- 解决AsyncTask引发的RejectedExecutionException
- AsyncTask, RejectedExecutionException and Task Limit
- java.util.concurrent.RejectedExecutionException for multi AsyncTask
- 解决AsyncTask引发的RejectedExecutionException
- Android线程池(二)——ThreadPoolExecutor及其拒绝策略RejectedExecutionHandler使用示例
- Android线程池(二)——ThreadPoolExecutor及其拒绝策略RejectedExecutionHandler使用示例
- Android N 版本迭代/应用内升级 FileUriExposedException问题处理
- Android开发笔记之:AsyncTask的应用详解