在我的应用程序中有一个 RecyclerView
,其中包含大量图像。当用户使用以下代码滚动 RecyclerView 时,图像被加载:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
loader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,url);
else
loader.execute(url);
不幸的是,有时当用户快速滚动时会发生此错误:
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]
有没有办法检测 poolExecutor 是否已满并跳过图像加载?
整个图像类:
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();
}
最佳答案
我之前回答过这个问题(here、here、here 和 here 可能还有其他),我再次为你回答:不要试图重新发明轮子!
图像加载/缓存在 Android 中是一项非常复杂的任务,许多优秀的开发人员已经做到了这一点。线程只是问题之一,但我可以从您的代码中看到您有内存泄漏,没有缓存,因此如果回滚到它,您将再次重新下载图像,HttpURLConnection
很糟糕网络层。
所以,解决这个问题的方法(恕我直言)就是重复使用其他开发人员完成的工作。您应该考虑的图书馆的好例子是:
- 毕加索 - https://github.com/square/picasso
- 滑行 - https://github.com/bumptech/glide
- 壁画 - https://github.com/facebook/fresco
Picasso 是我的最爱,所以要使用它你只需调用:
Picasso.with(context).load(url).into(imgView);
这一切都为您处理。
关于安卓:java.util.concurrent.ThreadPoolExecutor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44365214/