I read somewhere (and have observed) that starting threads is slow. I always assumed that AsyncTask created and reused a single thread because it required being started inside the UI thread.
The following (anonymized) code is called from a ListAdapter’s getView method to load images asynchronously. It works well until the user moves the list quickly, and then it becomes “janky“.
final File imageFile = new File(getCacheDir().getPath() + "/img/" + p.image);
image.setVisibility(View.GONE);
view.findViewById(R.id.imageLoading).setVisibility(View.VISIBLE);
(new AsyncTask<Void, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Void... params) {
try {
Bitmap image;
if (!imageFile.exists() || imageFile.length() == 0) {
image = BitmapFactory.decodeStream(new URL(
"http://example.com/images/"
+ p.image).openStream());
image.compress(Bitmap.CompressFormat.JPEG, 85,
new FileOutputStream(imageFile));
image.recycle();
}
image = BitmapFactory.decodeFile(imageFile.getPath(),
bitmapOptions);
return image;
} catch (MalformedURLException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
return null;
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
return null;
}
}
@Override
protected void onPostExecute(Bitmap image) {
if (view.getTag() != p) // The view was recycled.
return;
view.findViewById(R.id.imageLoading).setVisibility(
View.GONE);
view.findViewById(R.id.image)
.setVisibility(View.VISIBLE);
((ImageView) view.findViewById(R.id.image))
.setImageBitmap(image);
}
}).execute();
I’m thinking that a queue-based method would work better, but I’m wondering if there is one or if I should attempt to create my own implementation.
The key is explained in the example List13.java
Basically you have to track the scroll state of your listView and notify
the adapter when it is ready to do something of slow with the just visibile
items.
Also note that saving images to the disk is a very slow process. Using a
memory-based cache stategy would improve a lot your perfomance’s
application.