문제

i'm trying to implement a image gallery, which should show ~ 5-15 smaller images and one "current selected" bigger image.

It looks like: http://www.mobisoftinfotech.com/blog/wp-content/uploads/2012/06/galleryDemo.png

I've looked up many sources and now decided to use a bitmap-cache (lru-cache) (thanks to a person from this forum!).

I don't get memory-leaks at the moment, but i'm not happy with this solution because everytime i scroll, some images are removed from the cache and i've to reload them... so the user has to wait for reloading images... It's really annoying to wait 0.5 - 1 second every time i scroll to the other side...

public static WeakReference<Bitmap> getBitmap(String imageName, int width,
        int height) {
    if (!imageName.contains(".jpg")){
        imageName += ".jpg";
    }
    String pathToImage = getPathToImage(imageName);
    Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(pathToImage, options);

    /*
     * Calculate inSampleSize
     */
    options.inSampleSize = calculateInSampleSize(options, width, height);

    /*
     * Removes the alpha-channel from bitmap (not necessary)
     */
    options.inPreferredConfig = Bitmap.Config.RGB_565;

    /*
     * Decode bitmap with inSampleSize set
     */
    options.inJustDecodeBounds = false;

    WeakReference<Bitmap> scaledBitmap = new WeakReference<Bitmap>(
            BitmapFactory.decodeFile(pathToImage, options));
    return scaledBitmap;

Is it possible that i make a mistake in getting the images? At the moment i'll use 320x480 resolution for the single-selected image and 64x64 for the list on the bottom...

Really weird is the fact, that it doesn't matter, how big the resolutions of the images are, the lru-cache will still remove some images, even if i choose only 64x64 images... I might be doing wrong something with the lru cache?

The following code shows my implementation:

    /*
     * Bitmaps which should be shown
     */
    mMemoryCache = (BitmapCache) getLastNonConfigurationInstance();
    if (mMemoryCache == null) {
        // 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/4th of the available memory for this memory cache.
        final int cacheSize = maxMemory / 2; // TODO default 8

        mMemoryCache = new BitmapCache(cacheSize);
    }

And the Class BitmapCache:

public BitmapCache(int maxSize, Resources resources) {
    super(maxSize);
    this.resources = resources;
}

@Override
protected int sizeOf(String key, AsyncDrawable value) {
    if (value.getBitmap() != null) {
        /* 
         * The cache size will be measured in kilobytes rather than
         * number of items.
         */
        return value.getBitmap().getRowBytes()
                * value.getBitmap().getHeight() / 1024;
    }
    return super.sizeOf(key, value);
}

public void loadBitmap(Picture picture, ImageView mImageView,
        ImageResolution resolution) {
    if (cancelPotentialWork(picture.getFileName(), //  + resolution.name()
            mImageView)) {
        final BitmapWorkerTask task = new BitmapWorkerTask(this,
                mImageView, picture, resolution);
        final AsyncDrawable asyncDrawable = new AsyncDrawable(resources,
                null, task);
        mImageView.setImageDrawable(asyncDrawable);
        task.execute();
    }
}

Thank you very much :(

Some more code: BitmapWorkerTask:

@Override
protected Bitmap doInBackground(Void... params) {
    /*
     *  Decode image in background.
     */
    final Bitmap bitmap = FileHandler.getBitmap(
            picture.getPictureId() + "", resolution).get();
    return bitmap;
}

@Override
protected void onPostExecute(Bitmap bitmap) {
    /*
     *  Once complete, see if ImageView is still around and set bitmap.
     */
    if (isCancelled()) {
        bitmap = null;
    }

    if (imageViewReference != null && bitmap != null) {
        final ImageView imageView = imageViewReference.get();

        if (imageView != null) {
            final Drawable drawable = imageView.getDrawable();
            if (drawable instanceof AsyncDrawable) {
                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
                final BitmapWorkerTask bitmapWorkerTask = asyncDrawable
                        .getBitmapWorkerTask();
                if (this == bitmapWorkerTask && imageView != null) {
                    imageView.setImageBitmap(bitmap);
                    bitmapCache.addBitmapToMemoryCache(
                            picture.getFileName(), // + resolution.name()
                            asyncDrawable);
                }
            }
        }
    }
}
도움이 되었습니까?

해결책

AWESOME! I found the mistake why it couldn't work. The fault was in my LruCache, which stored AsyncDrawables, what is totally dumb. Everytime sizeOf in the LruCache was called, the bitmap inside of the asyncdrawable was null, so he just returned super.sizeOf(key, value).

Now it works like a charm!! :)

Thanks for your helps!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top