Hi everyone, i complete the the first challenge, and i use LruCache to cache bitmap, downloaded by FlickrFetcher().getUrlBytes()
.Then I check LruCache in queueThumbnail()
method, and I call onThumbnailDownloaded
if bitmap is not null.
public void queueThumbnail(T target, String url) {
Log.i(TAG, "Got a URL: " + url);
if (url == null) {
mRequestMap.remove(target);
} else {
mRequestMap.put(target, url);
Bitmap bitmap;
if ((bitmap = mCaches.get(url)) != null) {
if (mThumbnailDownloadListener != null) {
mThumbnailDownloadListener.onThumbnailDownloaded(target, bitmap);
}
Log.i(TAG, "Got a URL: " + url + " from cache");
return;
}
mRequestHandler.obtainMessage(MESSAGE_DOWNLOAD, target).sendToTarget();
}
}
But I have some problem for the second challenge. I extract the part of download image to a method called getBitmap()
:
private Bitmap getBitmap(String url) {
try {
byte[] bytes = new FlickrFetcher().getUrlBytes(url);
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
mCaches.put(url, bitmap);
Log.i(TAG, "Bitmap created");
return bitmap;
} catch (IOException e) {
Log.e(TAG, "Error downloading image", e);
e.printStackTrace();
}
return null;
}
Then, I add a method called preLoad to send MESSAGE_PREDOWNLOAD
Message
to mRequestHandler
, the request handler invoke getBitmap()
and add downloaded bitmap to lrucache:
public void preLoad(String url) {
if (url == null) {
return;
}
if (mCaches.get(url) == null) {
mRequestHandler.obtainMessage(MESSAGE_PREDOWNLOAD, url).sendToTarget();
}
}
@Override
protected void onLooperPrepared() {
mRequestHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_DOWNLOAD) {
T target = (T) msg.obj;
Log.i(TAG, "Got a request for URL: " + mRequestMap.get(target));
handRequest(target);
} else if (msg.what == MESSAGE_PREDOWNLOAD) {
getBitmap((String) msg.obj);
}
}
};
}
Lastly, I add the content as follows in PhotoGalleryFragment:
class FetchItemsTask extends AsyncTask<Void, Void, List<GalleryItem>> {
@Override
protected List<GalleryItem> doInBackground(Void... voids) {
return new FlickrFetcher().fetchItems();
}
@Override
protected void onPostExecute(List<GalleryItem> galleryItems) {
mGalleryItems = galleryItems;
preLoad(0, 10);
setupAdapter();
}
}
private void preLoad(int start, int count) {
start = start < 0 ? 0 : start;
count = count < mGalleryItems.size() ? count : mGalleryItems.size();
for (int i = start; i < count; i++) {
mThumbnailDownloader.preLoad(mGalleryItems.get(i).getUrl());
}
}
class PhotoHolder extends RecyclerView.ViewHolder {
ImageView mImageView;
public PhotoHolder(View itemView) {
super(itemView);
mImageView = itemView.findViewById(R.id.item_image_view);
}
public void bind(Drawable drawable) {
mImageView.setImageDrawable(drawable);
}
}
class PhotoAdapter extends RecyclerView.Adapter<PhotoHolder> {
private List<GalleryItem> mItems;
public PhotoAdapter(@NonNull List<GalleryItem> items) {
this.mItems = items;
}
@NonNull
@Override
public PhotoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(getActivity()).inflate(R.layout.list_item_gallery, parent, false);
return new PhotoHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull PhotoHolder holder, int position) {
GalleryItem item = mGalleryItems.get(position);
Drawable placeHolder = getResources().getDrawable(R.drawable.img_placeholder);
holder.bind(placeHolder);
mThumbnailDownloader.queueThumbnail(holder, item.getUrl());
preLoad(position - 10, position);
preLoad(position, position + 10);
}
@Override
public int getItemCount() {
return mItems.size();
}
}
I add preLoad(int start, int count)
method , and invoke it in two place: onPostExecute and onBindViewHolder.But I get the worse result than before, because the behavior of preload occupied network resource, resulting in the normal item that need display can’t download image quickly.
So how I can do to solve this problem.