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

Glide NPE #2413

Closed
liufsd opened this issue Sep 20, 2017 · 11 comments
Closed

Glide NPE #2413

liufsd opened this issue Sep 20, 2017 · 11 comments
Labels
Milestone

Comments

@liufsd
Copy link

liufsd commented Sep 20, 2017

version

 compile ('com.github.bumptech.glide:glide:4.2.0-SNAPSHOT'){
        exclude module: 'support-annotations'
    }

crash:

java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.drawable.Drawable com.bumptech.glide.request.RequestOptions.getFallbackDrawable()' on a null object reference
 at com.bumptech.glide.request.SingleRequest.getFallbackDrawable(:361)
 at com.bumptech.glide.request.SingleRequest.setErrorPlaceholder(:402)
 at com.bumptech.glide.request.SingleRequest.onLoadFailed(:571)
 at com.bumptech.glide.request.SingleRequest.onLoadFailed(:553)
 at com.bumptech.glide.load.engine.EngineJob.handleExceptionOnMainThread(:259)
 at com.bumptech.glide.load.engine.EngineJob$iF.handleMessage(:291)
 at android.os.Handler.dispatchMessage(Handler.java:98)
 at android.os.Looper.loop(Looper.java:135)
 at android.app.ActivityThread.main(ActivityThread.java:5309)
 at java.lang.reflect.Method.invoke(Native Method)
 at java.lang.reflect.Method.invoke(Method.java:372)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)

@Muyangmin
Copy link
Contributor

Thanks for your feedback! Can you provide more details:

  1. What do you set as placeholder, error, and fallback drawables?
  2. How do you load it (load line code)?
  3. Is there any available sample on GitHub can directly reproduce this?

@liufsd
Copy link
Author

liufsd commented Sep 20, 2017

//load network gif image

   Glide.with(context)
                        .load(imageUri)
                        .apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.AUTOMATIC))
                        .apply(RequestOptions().placeholder(imageView.context.resources.getDrawable(holderConfig?.loading ?: R.drawable.emoticon_image_show_loading)))
                        .apply(RequestOptions().error(imageView.context.resources.getDrawable(holderConfig?.error ?: R.drawable.emoticon_image_show_retry)))
                        .listener(object : RequestListener<Drawable> {
                            override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
                                loadImageCompleteListener?.onLoadImageComplete(false)
                                return false
                            }

                            override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                                loadImageCompleteListener?.onLoadImageComplete(true)
                                return false
                            }
                        })
                        .into(imageView)

@Muyangmin
Copy link
Contributor

Sorry, I've tried with kotlin 1.1.4-3, glide 4.2.0-SNAPSHOT, and also tried using java code, with following condition variables in your pasted code:

  • imageUri == null
  • placeholder == null
  • error == null

but cannot reproduce this crash.

Are you trying (or maybe potentially caused by some lifecycle logic) to use an image request that maybe already removed from RequestManager?

Or maybe you can waiting for @sjudd for help 😝

@liufsd
Copy link
Author

liufsd commented Sep 20, 2017

sorry , i do not known this case. sometimes crash.

@spatenotte
Copy link

spatenotte commented Sep 21, 2017

Bumping this up, I'm having the same issue (on Glide 4.1.1), seems to happen after a request times out.
Also not sure if it's related, but the first image's size seems to be invalid, and has both height and width set to what looks like Int's minimum value (Integer.MIN_VALUE). (edit: Repro'ed the crash without invalid image size, so it's not related to that)

09-21 11:01:59.038 W/Glide: Load failed for [Image URL] with size [-2147483648x-2147483648]
    class com.bumptech.glide.load.engine.GlideException: Failed to load resource
      Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, REMOTE
        Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetch failed
          Cause (1 of 1): class java.net.SocketTimeoutException: connect timed out

09-21 11:01:59.038 I/Glide: Root cause (1 of 1)
    java.net.SocketTimeoutException: connect timed out
        at java.net.PlainSocketImpl.socketConnect(Native Method)
        at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:334)
        at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:196)
        at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:178)
        at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:356)
        at java.net.Socket.connect(Socket.java:586)
        at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:63)
        at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:223)
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:149)
        at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:195)
        at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
        at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
        at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)
        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
        at java.lang.Thread.run(Thread.java:761)

09-21 11:02:01.388 W/Glide: Load failed for [Image URL] with size [1080x1475]
    class com.bumptech.glide.load.engine.GlideException: Failed to load resource
      Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, REMOTE
        Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetch failed
          Cause (1 of 1): class java.net.SocketTimeoutException: SSL handshake timed out

09-21 11:02:01.388 I/Glide: Root cause (1 of 1)
    java.net.SocketTimeoutException: SSL handshake timed out
        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:357)
        at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.java:281)
        at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.java:251)
        at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:151)
        at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:195)
        at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121)
        at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:185)
        at okhttp3.RealCall$AsyncCall.execute(RealCall.java:135)
        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
        at java.lang.Thread.run(Thread.java:761)

09-21 11:02:01.392 D/AndroidRuntime: Shutting down VM

09-21 11:02:01.435 E/Application: === APPLICATION CRASH ===
    java.lang.NullPointerException: Attempt to invoke virtual method 'android.graphics.drawable.Drawable com.bumptech.glide.request.RequestOptions.getFallbackDrawable()' on a null object reference
        at com.bumptech.glide.request.SingleRequest.getFallbackDrawable(SingleRequest.java:361)
        at com.bumptech.glide.request.SingleRequest.setErrorPlaceholder(SingleRequest.java:402)
        at com.bumptech.glide.request.SingleRequest.onLoadFailed(SingleRequest.java:571)
        at com.bumptech.glide.request.SingleRequest.onLoadFailed(SingleRequest.java:553)
        at com.bumptech.glide.load.engine.EngineJob.handleExceptionOnMainThread(EngineJob.java:259)
        at com.bumptech.glide.load.engine.EngineJob$MainThreadCallback.handleMessage(EngineJob.java:291)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6077)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

@sjudd
Copy link
Collaborator

sjudd commented Sep 21, 2017

Let me know if you can reproduce this.

One way I think this can happen is if a DataFetcher calls onLoadFailed twice, or if it calls both onResourceReady and onLoadFailed.

@spatenotte
Copy link

I disabled cache and was able to reproduce it 100% of times.

You are right, it seems in my case it happens because when it fails for the first time, we retry the request. When it fails for a second time, that's when the crash happens. Removing the retry stops the crashes.

Thanks! I'll consider this as solved for me :)

@sjudd
Copy link
Collaborator

sjudd commented Sep 21, 2017

Can you show the retry you're using? You actually can retry in a DataFetcher, you just can't call the callbacks until the retries are finished.

@spatenotte
Copy link

This was probably a terrible idea, in hindsight, but here goes:

GlideApp.with(Application.getContext())
        .load(url)
        .placeholder(defaultImageRes)
        .error(defaultImageRes)
        .listener(new RequestListener<Drawable>() {
            @Override
            public boolean onLoadFailed(@Nullable final GlideException e, final Object model,
                    final Target<Drawable> target, final boolean isFirstResource) {
                GlideApp.with(imageView)
                        .load(url)
                        .placeholder(defaultImageRes)
                        .error(defaultImageRes)
                        .listener(new RequestListener<Drawable>() {
                            @Override
                            public boolean onLoadFailed(@Nullable final GlideException e, final Object model,
                                    final Target<Drawable> target, final boolean isFirstResource) {
                                if (onError != null) {
                                    onError.run();
                                }
                                return false;
                            }

                            @Override
                            public boolean onResourceReady(final Drawable resource, final Object model,
                                    final Target<Drawable> target, final DataSource dataSource,
                                    final boolean isFirstResource) {
                                if (onSuccess != null) {
                                    onSuccess.run();
                                }
                                return false;
                            }
                        })
                        .into(imageView);
                return false;
            }

            @Override
            public boolean onResourceReady(final Drawable resource, final Object model,
                    final Target<Drawable> target, final DataSource dataSource, final boolean isFirstResource) {
                if (onSuccess != null) {
                    onSuccess.run();
                }
                return false;
            }
        })
        .into(imageView);

@sjudd
Copy link
Collaborator

sjudd commented Sep 21, 2017

Ah I got it, thanks that's super helpful. So I think you actually can make that work by posting your second load in onLoadFailed:

@Override
public boolean onLoadFailed(@Nullable final GlideException e, final Object model,
     final Target<Drawable> target, final boolean isFirstResource) {
  new Handler(Looper.getMainLooper()).post(new Runnable() {
      @Override
      public void run() {
        Glide.with(imageView)....
     });
}

In your case this error occurs because your second load actually recycles the first request while the first request is in the middle of running it's load failed logic so that by the time your request listener finishes running, all of its state has been cleared out.

I can't trivially fix that, but I can probably at least make it throw a reasonable exception most of the time that will make it more obvious what isn't working.

@sjudd sjudd added the bug label Sep 21, 2017
@sjudd sjudd added this to the 4.2 milestone Sep 21, 2017
@spatenotte
Copy link

Yeah, that actually works, awesome!

Thanks for the help, hope it helps @liufsd as well.

@sjudd sjudd closed this as completed in 6fb87b3 Sep 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants