Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

diskCacheStrategy does't work on glide:4.0.0-RC0 #1960

Closed
spidulica opened this issue May 23, 2017 · 8 comments
Closed

diskCacheStrategy does't work on glide:4.0.0-RC0 #1960

spidulica opened this issue May 23, 2017 · 8 comments

Comments

@spidulica
Copy link

spidulica commented May 23, 2017

Glide Version: glide:4.0.0-RC0

Integration libraries:

dependencies {
    compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
    compile 'com.android.support:support-v4:25.3.1'
}

Device/Android Version: Nexus 5

Issue details / Repro steps / Use case background:
In RecyclerView when refresh ui the image flicker.

Glide load line / GlideModule (if any) / list Adapter code (if any):

 Glide.with(activity.getApplicationContext())
                .asBitmap()
                .load(path)
                .apply(new RequestOptions()
                        .placeholder(R.drawable.placeholder_file_16_9)
                        .error(R.drawable.corrupted_file_16_9)
                        .transform(new PositionedCropTransformation(activity, 0, 0))
                        .diskCacheStrategy(DiskCacheStrategy.DATA)
                )

                .listener(new RequestListener<Bitmap>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                        updateGlideUi(holder);
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                        updateGlideUi(holder);
                        return false;
                    }
                })
                .into(holder.imageMsg);

Layout XML:

 <LinearLayout
        android:id="@+id/chat_item_container_user_image"
        android:layout_width="@dimen/dimen_50dp"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_below="@id/chat_item_timestamp"
        android:layout_marginEnd="@dimen/dimen_7dp">

        <ImageView
            android:id="@+id/chat_item_user_image"
            android:layout_width="@dimen/dimen_38dp"
            android:layout_height="@dimen/dimen_38dp"
            android:layout_gravity="top"
            android:scaleType="centerCrop" />
    </LinearLayout>

Stack trace / LogCat:

paste stack trace and/or log here
@spidulica
Copy link
Author

the path is a url

@TWiStErRob
Copy link
Collaborator

Disk cache is still async, not sure what you're expecting from it. It's not quantum computing yet.

What is updateGlideUi?

@spidulica
Copy link
Author

In version 3.7 after load a image from url, when call RecyclerView.notifyDataSetChanged() whith .diskCacheStrategy(DiskCacheStrategy.SOURCE) the image doesn't flicker. Now it flicker, what can i do in this case?
In updateGlide i show or hide some view elements.

@spidulica
Copy link
Author

The flicker is caused by the .transform(new PositionedCropTransformation(activity, 0, 0)).

@spidulica
Copy link
Author

This is class use in .transform.

/**
 * Created by bjornson on 27.09.16.
 */
public class PositionedCropTransformation extends BitmapTransformation {
    private static final String ID = "PositionedCropTransformation.com.bumptech.glide.load.resource.bitmap.x:0.y:0";
    private static final byte[] ID_BYTES = ID.getBytes(Key.CHARSET);

    private static final List<String> MODELS_REQUIRING_BITMAP_LOCK =
            Arrays.asList("XT1097", "XT1085");

    private static final Lock BITMAP_DRAWABLE_LOCK =
            MODELS_REQUIRING_BITMAP_LOCK.contains(Build.MODEL)
                    && Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1
                    ? new ReentrantLock() : new NoLock();


    private float xPercentage = 0.5f;
    private float yPercentage = 0.5f;



    public PositionedCropTransformation(@FloatRange(from = 0.0, to = 1.0) float xPercentage, @FloatRange(from = 0.0, to = 1.0) float yPercentage) {
        this.xPercentage = xPercentage;
        this.yPercentage = yPercentage;
    }


    // Bitmap doesn't implement equals, so == and .equals are equivalent here.
    @SuppressWarnings("PMD.CompareObjectsWithEquals")
    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        return crop(pool, toTransform, outWidth, outHeight, xPercentage, yPercentage);
    }

    /**
     * A potentially expensive operation to crop the given Bitmap so that it fills the given dimensions. This operation
     * is significantly less expensive in terms of memory if a mutable Bitmap with the given dimensions is passed in
     * as well.
     *
     * @param pool     The BitmapPool to obtain a bitmap from.
     * @param inBitmap   The Bitmap to resize.
     * @param width    The width in pixels of the final Bitmap.
     * @param height   The height in pixels of the final Bitmap.
     * @param xPercentage The horizontal percentage of the crop. 0.0f => left, 0.5f => center, 1.0f => right or anything in between 0 and 1
     * @param yPercentage The vertical percentage of the crop. 0.0f => top, 0.5f => center, 1.0f => bottom or anything in between 0 and 1
     * @return The resized Bitmap (will be recycled if recycled is not null).
     */
    private static Bitmap crop(BitmapPool pool, Bitmap inBitmap, int width, int height, float xPercentage, float yPercentage) {
        if (inBitmap.getWidth() == width && inBitmap.getHeight() == height) {
            return inBitmap;
        }

        // From ImageView/Bitmap.createScaledBitmap.
        final float scale;
        float dx = 0, dy = 0;
        Matrix m = new Matrix();
        if (inBitmap.getWidth() * height > width * inBitmap.getHeight()) {
            scale = (float) height / (float) inBitmap.getHeight();
            dx = (width - inBitmap.getWidth() * scale);
            dx *= xPercentage;
        } else {
            scale = (float) width / (float) inBitmap.getWidth();
            dy = (height - inBitmap.getHeight() * scale);
            dy *= yPercentage;
        }

        m.setScale(scale, scale);
        m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));

        Bitmap result = pool.get(width, height, getSafeConfig(inBitmap));
        // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
        TransformationUtils.setAlpha(inBitmap, result);

        applyMatrix(inBitmap, result, m);
        return result;
    }

    private static void applyMatrix(@NonNull Bitmap inBitmap, @NonNull Bitmap targetBitmap,
                                    Matrix matrix) {
        BITMAP_DRAWABLE_LOCK.lock();
        try {
            Canvas canvas = new Canvas(targetBitmap);
            canvas.drawBitmap(inBitmap, matrix, new Paint(PAINT_FLAGS));
            canvas.setBitmap(null);
        } finally {
            BITMAP_DRAWABLE_LOCK.unlock();
        }
    }

    private static Bitmap.Config getSafeConfig(Bitmap bitmap) {
        return bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
    }

    @Override
    public int hashCode() {
        return ID.hashCode();
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(ID_BYTES);
    }


    private static final class NoLock implements Lock {

        @Synthetic
        NoLock() { }

        @Override
        public void lock() {
            // do nothing
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
            // do nothing
        }

        @Override
        public boolean tryLock() {
            return true;
        }

        @Override
        public boolean tryLock(long time, @NonNull TimeUnit unit) throws InterruptedException {
            return true;
        }

        @Override
        public void unlock() {
            // do nothing
        }

        @NonNull
        @Override
        public Condition newCondition() {
            throw new UnsupportedOperationException("Should not be called");
        }
    }
}

@sjudd
Copy link
Collaborator

sjudd commented May 24, 2017

Thanks for providing the code!

It looks like you've implemented hashCode() in your Transformation, but not equals(). Add an implementation for equals() and try again.

@spidulica
Copy link
Author

Thanks this was the problem. Last version of code:

/**
 * Created by bjornson on 27.09.16.
 */
public class PositionedCropTransformation extends BitmapTransformation {
    private static final String ID = "PositionedCropTransformation.com.bumptech.glide.load.resource.bitmap.x:0.y:0";
    private static final byte[] ID_BYTES = ID.getBytes(Key.CHARSET);

    private float xPercentage = 0.5f;
    private float yPercentage = 0.5f;



    public PositionedCropTransformation(@FloatRange(from = 0.0, to = 1.0) float xPercentage, @FloatRange(from = 0.0, to = 1.0) float yPercentage) {
        this.xPercentage = xPercentage;
        this.yPercentage = yPercentage;
    }


    // Bitmap doesn't implement equals, so == and .equals are equivalent here.
    @SuppressWarnings("PMD.CompareObjectsWithEquals")
    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        return crop(pool, toTransform, outWidth, outHeight, xPercentage, yPercentage);
    }

    /**
     * A potentially expensive operation to crop the given Bitmap so that it fills the given dimensions. This operation
     * is significantly less expensive in terms of memory if a mutable Bitmap with the given dimensions is passed in
     * as well.
     *
     * @param pool     The BitmapPool to obtain a bitmap from.
     * @param inBitmap   The Bitmap to resize.
     * @param width    The width in pixels of the final Bitmap.
     * @param height   The height in pixels of the final Bitmap.
     * @param xPercentage The horizontal percentage of the crop. 0.0f => left, 0.5f => center, 1.0f => right or anything in between 0 and 1
     * @param yPercentage The vertical percentage of the crop. 0.0f => top, 0.5f => center, 1.0f => bottom or anything in between 0 and 1
     * @return The resized Bitmap (will be recycled if recycled is not null).
     */
    private static Bitmap crop(BitmapPool pool, Bitmap inBitmap, int width, int height, float xPercentage, float yPercentage) {
        if (inBitmap.getWidth() == width && inBitmap.getHeight() == height) {
            return inBitmap;
        }

        // From ImageView/Bitmap.createScaledBitmap.
        final float scale;
        float dx = 0, dy = 0;
        Matrix m = new Matrix();
        if (inBitmap.getWidth() * height > width * inBitmap.getHeight()) {
            scale = (float) height / (float) inBitmap.getHeight();
            dx = (width - inBitmap.getWidth() * scale);
            dx *= xPercentage;
        } else {
            scale = (float) width / (float) inBitmap.getWidth();
            dy = (height - inBitmap.getHeight() * scale);
            dy *= yPercentage;
        }

        m.setScale(scale, scale);
        m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));

        Bitmap result = pool.get(width, height, getSafeConfig(inBitmap));
        // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
        TransformationUtils.setAlpha(inBitmap, result);

        applyMatrix(inBitmap, result, m);
        return result;
    }

    private static void applyMatrix(@NonNull Bitmap inBitmap, @NonNull Bitmap targetBitmap,
                                    Matrix matrix) {
       TransformationUtils.getBitmapDrawableLock().lock();
        try {
            Canvas canvas = new Canvas(targetBitmap);
            canvas.drawBitmap(inBitmap, matrix, new Paint(PAINT_FLAGS));
            canvas.setBitmap(null);
        } finally {
            TransformationUtils.getBitmapDrawableLock().unlock();
        }
    }

    private static Bitmap.Config getSafeConfig(Bitmap bitmap) {
        return bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
    }

    @Override
    public int hashCode() {
        return ID.hashCode();
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        messageDigest.update(ID_BYTES);
    }

    @Override
    public boolean equals(Object o) {
        return o instanceof PositionedCropTransformation;
    }
}

@sjudd
Copy link
Collaborator

sjudd commented May 24, 2017

Great, glad it works!

@sjudd sjudd closed this as completed May 24, 2017
@sjudd sjudd added the v4 label May 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants