In my app there is RecyclerView
with tons of images in it.Images are loaded as user scrolls RecyclerView with this code:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,url);
else
loader.execute(url);
Unfortunately sometimes when user scrolls fast this error occurs:
Task android.os.AsyncTask$3@73f1d84 rejected from
java.util.concurrent.ThreadPoolExecutor@8f5f96d[Running, pool size = 9,
active threads = 9, queued tasks = 128, completed tasks = 279]
Is there way to detect if poolExecutor is full and skip image loading?
Whole Image class:
public class Image extends ImageView {
private AsyncTask<String,Integer,Bitmap> loader;
public Image(Context context) {
super(context);
this.setScaleType(ScaleType.FIT_XY);
}
public Image(Context context, AttributeSet attrs) {
super(context, attrs);
this.setScaleType(ScaleType.FIT_XY);
}
public void loadURL(String url) {
if(loader!=null)
loader.cancel(true);
loader=new AsyncTask<String, Integer, Bitmap>() {
@Override
protected Bitmap doInBackground(String... params) {
URL url = null;
byte[] bytes = null;
HttpURLConnection connection=null;
try {
url = new URL(params[0]);
connection=(HttpURLConnection) url.openConnection();
connection.setRequestProperty("Connection", "close");
connection.setRequestMethod("GET");
connection.setUseCaches(true);
InputStream is = null;
is=connection.getInputStream();
bytes = IOUtils.toByteArray(is);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (connection!=null)
connection.disconnect();
Bitmap res=null;
if(!isCancelled() && bytes!=null)
res=BitmapFactory.decodeByteArray(bytes,0,bytes.length);
return res;
}
@Override
protected void onPostExecute(Bitmap res) {
if(res!=null) {
setImageBitmap(res);
_animate();
}
}
};
if (this.getDrawable()!=null) {
Bitmap bmp=((BitmapDrawable) this.getDrawable()).getBitmap();
this.setAnimation(null);
if (bmp!=null) {
bmp.recycle();
//Log.d("image","recycled");
}
this.setImageBitmap(null);
}
/*
ThreadPoolExecutor e =(ThreadPoolExecutor) Executors.newFixedThreadPool(9);
Log.d("pool size",e.getActiveCount()+"/"+e.getMaximumPoolSize());
if (e.getActiveCount() == e.getMaximumPoolSize()) {
}
*/
//start loading
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
else
loader.execute(url);
}
private void _animate() {
ValueAnimator bgAnim= ValueAnimator.ofObject(new IntEvaluator(),0,255);
bgAnim.setDuration(500);
bgAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Image.this.getDrawable().setAlpha((int) (animation.getAnimatedValue()));
}
});
bgAnim.start();
}
}
I answer that before (here, here, here and here and probably others) and I answer it again for you: Do not try to re-invent the wheel!
Image loading/caching is a very complex task in Android and a lot of good very developers already did that. Threading is just one of the issues, but I can see from your code you have a memory leak, there's no caching so you'll re-download images again if scroll back to it, HttpURLConnection
is a crappy network layer.
So, the way to solve this (IMHO) it's just to re-use work done by other developers. Good examples of libraries you should consider for that are:
Picasso is my favorite, so to use it you need to simply call:
Picasso.with(context).load(url).into(imgView);
and it all be handled for you.
You can check if active threads count is equal to thread pool maximum size then your thread pool is full by using this
ThreadPoolExecutor e =(ThreadPoolExecutor)Executors.newFixedThreadPool(totalnofthreads);
if (e.getActiveCount() == e.getMaximumPoolSize())
{
}
I just relized I can wrap loading code with try/catch:
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
else
loader.execute(url);
} catch (RejectedExecutionException e){
e.printStackTrace();
}
Looks like this would be optional solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With