So I was able to solve the first part of the challenge, which was to use LruCache to cache the bitmaps when downloaded. This page from the Android Developers site was very helpful. Here is my solution for that part of the challenge. All code is done in ThumbnailDownloader.java:
First I added a private global variable for the LruCache:
private LruCache<String, Bitmap> mLruCache;
I then added these lines to the constructor for ThumbnailDownloader in order to to initialize mLruCache:
public ThumbnailDownloader(Handler responseHandler) {
super(TAG);
mResponseHandler = responseHandler;
***added***
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
*********
}
Next, I added these methods to the end of ThumbnailDownloader.java:
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mLruCache.put(key, bitmap);
}
}
public Bitmap getBitmapFromMemCache(String key) {
return mLruCache.get(key);
}
Lastly, I edited the handleRequest method to add the downloaded bitmaps to the cache, and to check the cache first for the images. If the image is not in the cache, it will download the image. Otherwise, it will take the image from the cache. I used the url for the image as the key:
private void handleRequest(final T target) {
try {
final String url = mRequestMap.get(target);
if(url == null) {
return;
}
***edited code***
final Bitmap bitmapFromMemCache = getBitmapFromMemCache(url);
if (bitmapFromMemCache != null) {
Log.i(TAG, "Bitmap found in cache");
mResponseHandler.post(new Runnable() {
@Override
public void run() {
if(mRequestMap.get(target) != url || mHasQuit) {
return;
}
mRequestMap.remove(target);
mThumbnailDownloadListener.onThumbnailDownloaded(target, bitmapFromMemCache);
}
});
} else {
byte[] bitmapBytes = new FlickrFetchr().getUrlBytes(url);
final Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0, bitmapBytes.length);
Log.i(TAG, "Bitmap created");
mResponseHandler.post(new Runnable() {
@Override
public void run() {
if(mRequestMap.get(target) != url || mHasQuit) {
return;
}
mRequestMap.remove(target);
addBitmapToMemoryCache(url, bitmap);
mThumbnailDownloadListener.onThumbnailDownloaded(target, bitmap);
}
});
}
****************
} catch (IOException ioe) {
Log.e(TAG, "Error downloading image", ioe);
}
}
This worked well for me for the first part of the challenge. However, I couldn’t quite figure out how to go about doing the preloading part of it. I tried implementing this into the onBindViewHolder of PhotoAdapter in PhotoGalleryFragment.java, but it didn’t work properly, repeated images at the end, and sometimes caused the app to crash:
if((mGalleryItems.size() - (position++)) < 10) {
for(int i = position; i > (position - 10); i--) {
GalleryItem galleryItem = mGalleryItems.get(i);
Drawable placeholder = getResources().getDrawable(R.drawable.ic_photo_grey_48dp);
holder.bindDrawable(placeholder);
mThumbnailDownloader.queueThumbnail(holder, galleryItem.getUrl());
}
for(int i = position; i < mGalleryItems.size(); i++) {
GalleryItem galleryItem = mGalleryItems.get(i);
Drawable placeholder = getResources().getDrawable(R.drawable.ic_photo_grey_48dp);
holder.bindDrawable(placeholder);
mThumbnailDownloader.queueThumbnail(holder, galleryItem.getUrl());
}
} else if(position < 10) {
for(int i = position; i >= 0; i--) {
GalleryItem galleryItem = mGalleryItems.get(i);
Drawable placeholder = getResources().getDrawable(R.drawable.ic_photo_grey_48dp);
holder.bindDrawable(placeholder);
mThumbnailDownloader.queueThumbnail(holder, galleryItem.getUrl());
}
for(int i = position; i < (position + 10); i++) {
GalleryItem galleryItem = mGalleryItems.get(i);
Drawable placeholder = getResources().getDrawable(R.drawable.ic_photo_grey_48dp);
holder.bindDrawable(placeholder);
mThumbnailDownloader.queueThumbnail(holder, galleryItem.getUrl());
}
} else {
for(int i = position; i > (position - 10); i--) {
GalleryItem galleryItem = mGalleryItems.get(i);
Drawable placeholder = getResources().getDrawable(R.drawable.ic_photo_grey_48dp);
holder.bindDrawable(placeholder);
mThumbnailDownloader.queueThumbnail(holder, galleryItem.getUrl());
}
for(int i = position; i < (position + 10); i++) {
GalleryItem galleryItem = mGalleryItems.get(i);
Drawable placeholder = getResources().getDrawable(R.drawable.ic_photo_grey_48dp);
holder.bindDrawable(placeholder);
mThumbnailDownloader.queueThumbnail(holder, galleryItem.getUrl());
}
}
I understand this is probably inefficient, but it’s what i could come up with on short notice. Any help would be greatly appreciated. @cstewart, any tips on where I should start?