Cache task with use of pure LRU*

*pure LRU - caching without use of picasso library
In ThumbnailDownloader I added:
private LruCache<String, Bitmap> mMemoryCache;
Updated constructor

    public ThumbnailDownloader(Handler responseHandler) {
                super(TAG);
                mResponseHandler = responseHandler;

                // Get max available VM memory, exceeding this amount will throw an
                // OutOfMemory exception. Stored in kilobytes as LruCache takes an
                // int in its constructor.
                final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

                // Use 1/8th of the available memory for this memory cache.
                final int cacheSize = maxMemory / 8;

                mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {

                    @Override
                    protected int sizeOf(String key, Bitmap value) {
                        // The cache size will be measured in kilobytes rather than
                        // number of items.
                        return value.getByteCount() / 1024;
                    }
                };
            }

added:

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (getBitmapFromMemoryCache(key) == null) {
            mMemoryCache.put(key, bitmap);
        }
    }

    public Bitmap getBitmapFromMemoryCache(String key) {
        return mMemoryCache.get(key);
    }

after that upd onLooperPrepared():

@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));
                    handleRequest(target);
                } else if (msg.what == MESSAGE_CACHE) {
                    T target = (T) msg.obj;
                    Log.i(TAG, "Got a request for cache URL: " + mRequestMap.get(target));
                    handleCacheRequest(target);
                }
            }
        };
    }

added:

public void queueThumbnailCache(String url) {
    Log.i(TAG, "Got a URL for cache: " + url);

    mRequestHandler.obtainMessage(MESSAGE_CACHE, url).sendToTarget();
}

and added:(I removed from handleRequest “addBitmapToMemoryCache(url, bitmap);”)

 private void handleCacheRequest(final T target) {
    final String url = (String)target;
    if (url == null) {
        return;
    }

    Log.d(TAG, "handleCacheRequest: " + url);

    final Bitmap bitmapFromMemoryCache = getBitmapFromMemoryCache(url);
    try {
        if (bitmapFromMemoryCache != null) {
            return;
        } else {
            byte[] bitmapBytes;
            bitmapBytes = new FlickrFetchr().getUrlBytes(url);
            final Bitmap bitmap = BitmapFactory
                    .decodeByteArray(bitmapBytes, 0, bitmapBytes.length);

            mResponseHandler.post(() -> {
                if (target != url || mHasQuit) {
                    return;
                }
                addBitmapToMemoryCache(url, bitmap);
            });
        }
    } catch (IOException e) {
        Log.e(TAG, "Error downloading image", e);
    }

}

In PhotoGalleryFragment:

Added:

private int mLastPosition;
private int mFirstPosition;

in onCreateView(…) we need smth like:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fragment_photo_gallery, container, false);
    mPhotoRecyclerView = v.findViewById(R.id.photo_recycler_view);
    mPhotoRecyclerView.getViewTreeObserver().
            addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    float columnWidthInPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                            140, getActivity().getResources().getDisplayMetrics());
                    int width = mPhotoRecyclerView.getWidth();
                    int columnNumber = Math.round(width / columnWidthInPixels);
                    mGridLayoutManager = new GridLayoutManager(getActivity(), columnNumber);
                    mPhotoRecyclerView.setLayoutManager(mGridLayoutManager);
                    mPhotoRecyclerView.scrollToPosition(mFirstPosition);
                    mPhotoRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                }
            });

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        mPhotoRecyclerView.setOnScrollChangeListener((v1, scrollX, scrollY, oldScrollX, oldScrollY) -> {
            mFirstPosition = mGridLayoutManager.findFirstVisibleItemPosition();
            mLastPosition = mGridLayoutManager.findLastVisibleItemPosition();
            if (!mUserScrolled) {
                if (mLastPosition == mItems.size() - 1) {
                    mUserScrolled = true;
                    Toast.makeText(getActivity(), "Bottom" + mLastPosition, Toast.LENGTH_SHORT).show();
                    new FetchItemsTask().execute();
                }
                //caching
                int top = (mFirstPosition > 10) ? mFirstPosition - 10 : 0;
                int bottom = mLastPosition > mItems.size() - 11 ?
                        mItems.size() : mLastPosition + 10;

                for (int i = top; i < bottom; i++) {
                    mThumbnailDownloader.queueThumbnailCache(mItems.get(i).getUrl());
                }
                //caching
            }

        });
    }
    setupAdapter();

    return v;
}
1 Like

Thanks for posting this. However, it appears your code is incomplete. Could you please post your full source code for PhotoGalleryFragment.java and ThumbnailDownloader.java?