split image cache into thumbnail- and cover-cache

This commit is contained in:
daniel oeh 2012-07-24 21:01:44 +02:00
parent 74b1fac152
commit d593d12e23
5 changed files with 123 additions and 48 deletions

View File

@ -48,7 +48,7 @@ public class FeedInfoActivity extends SherlockActivity {
txtvDescription = (TextView) findViewById(R.id.txtvDescription);
txtvLanguage = (TextView) findViewById(R.id.txtvLanguage);
txtvAuthor = (TextView) findViewById(R.id.txtvAuthor);
FeedImageLoader.getInstance().loadBitmap(feed.getImage(), imgvCover);
FeedImageLoader.getInstance().loadCoverBitmap(feed.getImage(), imgvCover);
txtvTitle.setText(feed.getTitle());
txtvDescription.setText(feed.getDescription());

View File

@ -92,9 +92,9 @@ public class FeedlistAdapter extends ArrayAdapter<Feed> {
} else {
holder.newEpisodes.setVisibility(View.INVISIBLE);
}
imageLoader.loadBitmap(feed.getImage(), holder.image);
holder.image.setTag(feed.getImage());
imageLoader.loadThumbnailBitmap(feed.getImage(), holder.image);
// TODO find new Episodes txtvNewEpisodes.setText(feed)
return convertView;
}

View File

@ -51,7 +51,7 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
Feed feed = (Feed) component;
holder.title.setText(feed.getTitle());
holder.subtitle.setVisibility(View.GONE);
FeedImageLoader.getInstance().loadBitmap(feed.getImage(),
FeedImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(),
holder.cover);
} else if (component.getClass() == FeedItem.class) {
@ -61,7 +61,7 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
holder.subtitle.setVisibility(View.VISIBLE);
holder.subtitle.setText(result.getSubtitle());
}
FeedImageLoader.getInstance().loadBitmap(item.getFeed().getImage(),
FeedImageLoader.getInstance().loadThumbnailBitmap(item.getFeed().getImage(),
holder.cover);
}

View File

@ -23,6 +23,9 @@ public class FeedImageLoader {
private static final String TAG = "FeedImageLoader";
private static FeedImageLoader singleton;
public static final int LENGTH_BASE_COVER = 200;
public static final int LENGTH_BASE_THUMBNAIL = 100;
/**
* Stores references to loaded bitmaps. Bitmaps can be accessed by the id of
* the FeedImage the bitmap belongs to.
@ -32,12 +35,28 @@ public class FeedImageLoader {
.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = 1024 * 1024 * memClass / 8;
private LruCache<Long, Bitmap> imageCache;
final int coverCacheSize = 1024 * 1024 * memClass / 10;
final int thumbnailCacheSize = 1024 * 1024 * memClass / 6;
private LruCache<Long, Bitmap> coverCache;
private LruCache<Long, Bitmap> thumbnailCache;
private FeedImageLoader() {
if (AppConfig.DEBUG) Log.d(TAG, "Creating cache with size " + cacheSize);
imageCache = new LruCache<Long, Bitmap>(cacheSize) {
coverCache = new LruCache<Long, Bitmap>(coverCacheSize) {
@SuppressLint("NewApi")
@Override
protected int sizeOf(Long key, Bitmap value) {
if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12)
return value.getByteCount();
else
return (value.getRowBytes() * value.getHeight());
}
};
thumbnailCache = new LruCache<Long, Bitmap>(thumbnailCacheSize) {
@SuppressLint("NewApi")
@Override
@ -60,18 +79,19 @@ public class FeedImageLoader {
}
@SuppressLint("NewApi")
public void loadBitmap(FeedImage image, ImageView target) {
public void loadCoverBitmap(FeedImage image, ImageView target) {
if (image != null) {
Bitmap bitmap = getBitmapFromCache(image.getId());
Bitmap bitmap = getBitmapFromCoverCache(image.getId());
if (bitmap != null) {
target.setImageBitmap(bitmap);
} else {
target.setImageResource(R.drawable.default_cover);
BitmapWorkerTask worker = new BitmapWorkerTask(target);
BitmapWorkerTask worker = new BitmapWorkerTask(target, image,
LENGTH_BASE_COVER);
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
worker.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, image);
worker.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
worker.execute(image);
worker.execute();
}
}
} else {
@ -79,42 +99,93 @@ public class FeedImageLoader {
}
}
public void addBitmapToCache(long id, Bitmap bitmap) {
imageCache.put(id, bitmap);
@SuppressLint("NewApi")
public void loadThumbnailBitmap(FeedImage image, ImageView target) {
if (image != null) {
Bitmap bitmap = getBitmapFromThumbnailCache(image.getId());
if (bitmap != null) {
target.setImageBitmap(bitmap);
} else {
target.setImageResource(R.drawable.default_cover);
BitmapWorkerTask worker = new BitmapWorkerTask(target, image,
LENGTH_BASE_THUMBNAIL);
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
worker.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
worker.execute();
}
}
} else {
target.setImageResource(R.drawable.default_cover);
}
}
public void wipeImageCache() {
imageCache.evictAll();
coverCache.evictAll();
thumbnailCache.evictAll();
}
public boolean isInCache(FeedImage image) {
return imageCache.get(image.getId()) != null;
public boolean isInThumbnailCache(FeedImage image) {
return thumbnailCache.get(image.getId()) != null;
}
public Bitmap getBitmapFromCache(long id) {
return imageCache.get(id);
public Bitmap getBitmapFromThumbnailCache(long id) {
return thumbnailCache.get(id);
}
class BitmapWorkerTask extends AsyncTask<FeedImage, Void, Void> {
/** The preferred width and height of a bitmap. */
private static final int LENGTH_BASE_VALUE = 200;
public void addBitmapToThumbnailCache(long id, Bitmap bitmap) {
thumbnailCache.put(id, bitmap);
}
public boolean isInCoverCache(FeedImage image) {
return coverCache.get(image.getId()) != null;
}
public Bitmap getBitmapFromCoverCache(long id) {
return coverCache.get(id);
}
public void addBitmapToCoverCache(long id, Bitmap bitmap) {
coverCache.put(id, bitmap);
}
class BitmapWorkerTask extends AsyncTask<Void, Void, Void> {
private int PREFERRED_LENGTH;
private static final String TAG = "BitmapWorkerTask";
private ImageView target;
private Bitmap bitmap;
private Bitmap decodedBitmap;
private int baseLength;
public BitmapWorkerTask(ImageView target) {
private FeedImage image;
public BitmapWorkerTask(ImageView target, FeedImage image, int length) {
super();
this.target = target;
this.PREFERRED_LENGTH = (int) (LENGTH_BASE_VALUE * PodcastApp.getLogicalDensity());
this.image = image;
this.baseLength = length;
this.PREFERRED_LENGTH = (int) (length * PodcastApp
.getLogicalDensity());
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
target.setImageBitmap(bitmap);
// check if imageview is still supposed to display this image
if (target.getTag() == null || target.getTag() == image) {
target.setImageBitmap(bitmap);
} else {
if (AppConfig.DEBUG)
Log.d(TAG, "Not displaying image");
}
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
private int calculateSampleSize(int width, int height) {
@ -139,50 +210,54 @@ public class FeedImageLoader {
}
@Override
protected Void doInBackground(FeedImage... params) {
protected Void doInBackground(Void... params) {
File f = null;
if (params[0].getFile_url() != null) {
f = new File(params[0].getFile_url());
if (image.getFile_url() != null) {
f = new File(image.getFile_url());
}
if (params[0].getFile_url() != null && f.exists()) {
if (image.getFile_url() != null && f.exists()) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(params[0].getFile_url(), options);
BitmapFactory.decodeFile(image.getFile_url(), options);
int sampleSize = calculateSampleSize(options.outWidth,
options.outHeight);
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
decodedBitmap = BitmapFactory.decodeFile(
params[0].getFile_url(), options);
decodedBitmap = BitmapFactory.decodeFile(image.getFile_url(),
options);
if (decodedBitmap == null) {
Log.i(TAG,
"Bitmap could not be decoded in custom sample size. Trying default sample size (path was "
+ params[0].getFile_url() + ")");
decodedBitmap = BitmapFactory.decodeFile(params[0]
+ image.getFile_url() + ")");
decodedBitmap = BitmapFactory.decodeFile(image
.getFile_url());
}
if (decodedBitmap != null) {
bitmap = Bitmap.createScaledBitmap(decodedBitmap,
PREFERRED_LENGTH, PREFERRED_LENGTH, false);
addBitmapToCache(params[0].getId(), bitmap);
bitmap = Bitmap.createScaledBitmap(decodedBitmap,
PREFERRED_LENGTH, PREFERRED_LENGTH, false);
if (baseLength == LENGTH_BASE_COVER) {
addBitmapToCoverCache(image.getId(), bitmap);
} else if (baseLength == LENGTH_BASE_THUMBNAIL) {
addBitmapToThumbnailCache(image.getId(), bitmap);
}
} else {
Log.w(TAG, "Could not load bitmap. Using default image.");
bitmap = BitmapFactory.decodeResource(target.getResources(),
R.drawable.default_cover);
bitmap = BitmapFactory.decodeResource(
target.getResources(), R.drawable.default_cover);
}
if (AppConfig.DEBUG) Log.d(TAG, "Finished loading bitmaps");
if (AppConfig.DEBUG)
Log.d(TAG, "Finished loading bitmaps");
} else {
Log.e(TAG,
"FeedImage has no valid file url. Using default image");
bitmap = BitmapFactory.decodeResource(target.getResources(),
R.drawable.default_cover);
if (params[0].getFile_url() != null
if (image.getFile_url() != null
&& !DownloadRequester.getInstance().isDownloadingFile(
params[0])) {
image)) {
FeedManager.getInstance().notifyInvalidImageFile(
PodcastApp.getInstance(), params[0]);
PodcastApp.getInstance(), image);
}
}
return null;

View File

@ -81,7 +81,7 @@ public class CoverFragment extends SherlockFragment {
}
private void loadMediaInfo() {
FeedImageLoader.getInstance().loadBitmap(
FeedImageLoader.getInstance().loadCoverBitmap(
media.getItem().getFeed().getImage(), imgvCover);
txtvTitle.setText(media.getItem().getTitle());
txtvFeed.setText(media.getItem().getFeed().getTitle());