bumptech / glide

An image loading and caching library for Android focused on smooth scrolling
https://bumptech.github.io/glide/
Other
34.65k stars 6.12k forks source link

Loading images blur on slow internet #1301

Closed venkymsnv closed 8 years ago

venkymsnv commented 8 years ago

We are using full request and thumbnail request to load the images from URLs.

fullRequest = Glide.with(this)
        .from(Photo.class)
        .centerCrop()
        .diskCacheStrategy(DiskCacheStrategy.RESULT)
        .crossFade(R.anim.fade_in, 150);

thumbnailRequest = Glide.with(this)
        .from(Photo.class)
        .diskCacheStrategy(DiskCacheStrategy.RESULT)
        .crossFade(R.anim.fade_in, 150)
        .override(400,400);

preloadRequest = thumbnail ? thumbnailRequest.clone().priority(Priority.HIGH) : fullRequest;

on getView method

fullRequest
        .load(current)
        .dontAnimate()
        .dontTransform()
        .placeholder(null)
        .thumbnail(thumbnail ? thumbnailRequest.load(current) : null)
        .into(imageView);

and our xml code

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:scaleType="centerCrop"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:contentDescription="@string/image_description" />

On Wi-Fi (about 4 mbps speed) images load perfectly

On 3G connection: It loads blur images initially and loads the perfect image with a slight delay. On 2G Connection: It is too blur and the images take more and more time to even load.

TWiStErRob commented 8 years ago

It seems to me you're describing how networks affect download times. Your thumbnail request is 400x400 px. If you have a large screen (e.g. fullHD or 4k), the small image will display blurred. What is the problem with this?

You can try using .sizeMultiplier() to load a proportional image for each device, instead of hard-coding a size.

venkymsnv commented 8 years ago

Thank you for the quick response.

We are trying to build the app as described below:

Can you suggest us a better way to perform this efficiently and effectively such that we can create a seamless experience on the App?

TWiStErRob commented 8 years ago

It looks like your "full" and "thumb" images are the same files, so consider:

thumbRequest = Glide.with(this)
        .from(Photo.class)
        .centerCrop()
        .diskCacheStrategy(DiskCacheStrategy.ALL) // save full image to disk cache when loading thumb
        .crossFade(R.anim.fade_in, 150);

getView ->
    thumbRequest.load(current).into(imageView);

and when you want to load the full-size image:

Glide.with(this)
        .load(photo)
        .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) // don't use target size, load full image
        .diskCacheStrategy(DiskCacheStrategy.SOURCE) // read original image from disk cache

This satisfies your requirements above, but I feel like you want more than you wrote down, specifically you want to display the thumbnail while loading the full-sized image. In that case you have to propagate the size of the thumbnail to where the full load happens and add:

.thumbnail(Glide.with(this)
    .load(photo) // model has to match
    .override(thumbW, thumbH) // size has to match
    .centerCrop() // transformation has to match
    .diskCacheStrategy(ALL) // makes it efficient by using the best possible cache
)

Take a look at #1279, #1186, and #1083 which deal with similar issues for transition (thumbnail need to be sync loaded in that case, from memory cache).

Also note that preloading, if any, should be done with lower priority to not block requests that need to be displayed immediately.

TWiStErRob commented 8 years ago

If you need more help please reopen and ask.

venkymsnv commented 8 years ago

Hi Rob,

Thanks for you response and time in replying to us. Your suggestions were very helpful for us and we appreciate your support.

Please let us know if we are doing this efficiently or can we enhance the loading of images and create a seamless experience.

We want to develop an application to display Backgrounds & wallpapers for Android mobiles. We wish to display images in 3 screens.

Screen 1: We are displaying images in a gridview as mentioned below:

In the MainActivity class

fullRequest = Glide.with(this)
        .from(Webphotos.class)
        .diskCacheStrategy(DiskCacheStrategy.ALL)
        .crossFade(R.anim.fade_in, 150);

thumbnailRequest = Glide.with(this)
        .from(Webphotos.class)
        .centerCrop()
        .diskCacheStrategy(DiskCacheStrategy.ALL)
        .crossFade(R.anim.fade_in, 150)
;

preloadRequest = true ? thumbnailRequest.clone().priority(Priority.HIGH) : fullRequest;

Adapter class thumbnail loading:

final Photos nature = photos.get(i);
NewPhotoActivity.thumbnailRequest
       .load(nature)
       .dontAnimate()
       .dontTransform()
       .placeholder(null)
       .thumbnail(1f)
       .into(((NormalViewHolder)viewHolder).imgThumbnail);

Preloading

@Override
public GenericRequestBuilder getPreloadRequestBuilder(Webphotos item) {
    return NewPhotoActivity.preloadRequest.load(item);
}

Screen 2:

Upon clicking an image in gridview I want to display the image in another activity (image size about 20-25% of screen height)

Glide.with(this)
        .load(photo)
        .placeholder(null)
        .diskCacheStrategy(DiskCacheStrategy.SOURCE)
        .into(fullscreenView);

But it is taking more time to display the image.

Screen 3: Upon clicking the fullscreen button in screen 2 we want to open a new activity with full screen image with out of bounds (height = screen size) and auto scroll the image from right to left and back until the user touches the screen.

Below are our current challenges:

  1. Displaying the images is consuming more time, can we make it faster?
  2. How to achieve full screen auto scroll image with out of bounds when clicking on fullscreen button.
  3. How can we make the App experience seamless, are there any tips on how to fetch the images faster?
  4. Is there any to use pre-loader efficiently with lower priority such that the immediate resources are not blocked.
  5. Our images are typically about 4-5 MB, how can we download them faster to phone storage upon clicking save?

Please have a glance at our demo, if time permits. link:

Thanks in advance for your help.

TWiStErRob commented 8 years ago

Screen 1

Remove .thumbnail(1f), it means: "load this photo, and load this photo as a thumbnail with the scale of one, which results in loading the exact same Bitmap twice. It's just wasting resources.

.crossFade() and .centerCrop() is negated on thumbnailRequest by .dontAnimate() and .dontTransform().

Displaying the images is consuming more time, can we make it faster?

It depends on where that time is spent, Glide cannot make downloads faster and 4-5 MB is huge. Consider server side thumbnail generation so when showing the grid you don't need to download 30MB worth of images when you could display the same UI using 400kB.

How can we make the App experience seamless, are there any tips on how to fetch the images faster?

Again, Glide is not a magic teleportation device: if you're downloading a huge image, it'll take time. Do you really need 4MB images to display a FullHD image? Most of the wallpaper sites serve multiple sizes of the images, pick the perfect fit and use that.

Is there any to use pre-loader efficiently with lower priority such that the immediate resources are not blocked.

Priority.HIGH -> Priority.LOW, because preloading is a background process to load ahead items that are not yet visible. Using a higher than normal priority will prefer those background loads stealing resources for stuff that should be visible already.

Screen 2

That looks like a reasonable load for that. SOURCE is good, because there wouldn't be much benefit of storing the 4th-screen tall image in cache.

Note: .placeholder(null) is the default.

Screen 3

How to achieve full screen auto scroll image with out of bounds when clicking on fullscreen button.

Scrolling is out of scope for Glide, but I think you can simply do it, if you put an ImageView in a ScrollView and animate the scroll position, which you cancel on user interaction. You can load the full sized image with .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL), but if you only want to allow sideways scrolling a better way (less memory, faster) would be .override(Target.SIZE_ORIGINAL, screenHeight).fitCenter().

Our images are typically about 4-5 MB, how can we download them faster to phone storage upon clicking save?

You can use .downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL).get() to get a File object from SOURCE cache, from there you can just copy that to any of the user's directories. The arguments to downloadOnly only matters if you use bucketing to dynamically determine the the url (=BaseGlideUrlLoader.getUrl actually uses the size arguments).