bumptech / glide

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

Requests canceling does not work with okhttp3-integration #3041

Open avdovichev opened 6 years ago

avdovichev commented 6 years ago

Glide Version: 4.6.1

Integration libraries: okhttp3-integration 4.6.1@aar, works fine with stock networking

Device/Android Version: Samsung SM-T531/4.4, Lenovo K33a42/7.0, stock emulator of Nexus 7 2012/8.0

Issue details / Repro steps / Use case background: Requests for ImageView widgets are not fully canceled. I prepared small demo project for easier problem understanding.

Steps to reproduce:

  1. Take this simple demo app: https://github.com/avdovichev/GlideTest and launch it
  2. See ImageView widgets arranged into grid. Initially, cells of grid contain placeholder image and with downloading progress they show images with theirs position numbers. In bottom-left corner application also shows last bound position. At this point everything is OK.
  3. Scroll down quickly and non-stop to latest position (predefined value is 4000, see current position in bottom-left corner).
  4. Once scrolling is completed see that images are not appearing for a long time. This is because requests for recycled ImageViews were not fully canceled. Server log shows that application downloads all images. And even last images were downloaded (appeared on the screen), application still may be downloading images for scrolled positions. This is first problem.
  5. After scrolling to the latest position wait for 5-10 minutes to let application download ~1700 - 1800 images.
  6. Try to scroll backwards a little - application will freeze or crash. Looks like there are some resources leakage. Logcat output contains complains about buffer allocation failures and many open files. This is the second problem. Most probably caused by first one.

Glide load line / GlideModule (if any) / list Adapter code (if any): @Override public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {

    final ImageView v = (ImageView) holder.itemView;

    Glide.with(context)
            .load("http://45.55.6.132/cards/" + String.valueOf(position + 1) + "/sample.png")
            .apply(new RequestOptions().placeholder(R.drawable.placeholder))
            .into(v)
            ;

    positionListener.onPositionChange(position); // to refresh last bound position
}

Layout XML: <?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="5dp" android:scaleType="fitCenter" android:adjustViewBounds="true" android:src="@drawable/placeholder" android:background="@android:color/black" />

Stack trace / LogCat: --- Android 4.4 ---- 04-22 23:27:38.427 6775-6775/com.example.glidetest W/Adreno-EGL: : EGL_BAD_SURFACE 04-22 23:27:38.427 6775-6775/com.example.glidetest W/HardwareRenderer: EGL error: EGL_BAD_SURFACE 04-22 23:27:38.437 6775-6775/com.example.glidetest W/HardwareRenderer: Mountain View, we've had a problem here. Switching back to software rendering. 04-22 23:27:38.547 6775-6775/com.example.glidetest E/Surface: dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: 1717840517 dequeueBuffer failed (Unknown error -1717840517) Surface::unlockAndPost failed, no locked buffer 04-22 23:27:38.567 6775-6775/com.example.glidetest E/ViewRootImpl: Could not unlock surface java.lang.IllegalArgumentException at android.view.Surface.nativeUnlockCanvasAndPost(Native Method) at android.view.Surface.unlockCanvasAndPost(Surface.java:281) at android.view.ViewRootImpl.drawSoftware(ViewRootImpl.java:2906) at android.view.ViewRootImpl.draw(ViewRootImpl.java:2805) at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2643) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2211) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6630) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803) 4-22 23:28:13.687 6775-6775/com.example.glidetest W/Glide: Load failed for http://45.55.6.132/cards/3970/sample.png with size [190x285] class com.bumptech.glide.load.engine.GlideException: Failed to load resource There were 2 causes: java.net.SocketException(socket failed: EMFILE (Too many open files)) java.io.FileNotFoundException(No content provider: http://45.55.6.132/cards/3970/sample.png) call GlideException#logRootCauses(String) for more detail Cause (1 of 2): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, REMOTE

--- Android 7.0 ---- 04-22 23:53:02.753 30781-30821/com.example.glidetest E/Parcel: dup() failed in Parcel::read, i is 0, fds[i] is -1, fd_count is 1, error: Too many open files 04-22 23:53:02.759 30781-30821/com.example.glidetest E/Surface: queueBuffer: error queuing buffer to SurfaceTexture, -22 04-22 23:53:02.760 30781-30821/com.example.glidetest I/Adreno: QueueBuffer: queueBuffer failed 04-22 23:53:02.761 30781-30821/com.example.glidetest W/OpenGLRenderer: swapBuffers encountered EGL error 12301 on 0x9e5ade20, halting rendering...

--- Android 8.0 ---- 04-23 00:03:33.329 12746-12746/com.example.glidetest W/Glide: Load failed for http://45.55.6.132/cards/3976/sample.png with size [186x279] class com.bumptech.glide.load.engine.GlideException: Failed to load resource There were 2 causes: java.net.SocketException(socket failed: EMFILE (Too many open files)) java.io.FileNotFoundException(No content provider: http://45.55.6.132/cards/3976/sample.png) call GlideException#logRootCauses(String) for more detail Cause (1 of 2): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, REMOTE There was 1 cause: java.net.SocketException(socket failed: EMFILE (Too many open files)) call GlideException#logRootCauses(String) for more detail

Why I use okhttp3 integration: Android versions prior to 5.0 have TLS v1.2 support turned off by default. Stock networking fails to get images from server where only TLS v1.2 is allowed. okhttp3 library turns TLS v1.2 support on and solves this problem.

Small demo project: https://github.com/avdovichev/GlideTest

Mountain View, we have a problem :)

avdovichev commented 6 years ago

Today I also checked Volley integration. It has no problems with requests canceling, but, alas, does not support TLS v1.2 on Android versions prior to 5.0

sjudd commented 6 years ago

Cancellation happens here: https://github.com/bumptech/glide/blob/a683e04d4bb794f82401abd2abfe975f664e2590/integration/okhttp3/src/main/java/com/bumptech/glide/integration/okhttp3/OkHttpStreamFetcher.java#L94.

Are you aware of anything else we could be doing to cancel the request?

We've had some resource leaks with OkHttp before, though as far as I know they were all in Glide and have previously been fixed.

avdovichev commented 6 years ago

I suspect that problem is actually in okhttp3 library. Once I have a free weekend I will make similar sandbox project with isolated okhttp3 testing and report results here.