Glide: OnResourceReady requires to run on UI thread (glide 4.9.0)

Created on 12 Apr 2019  路  7Comments  路  Source: bumptech/glide

The image is not loaded on the Glide version 4.9.0 while working well on glide 4.8.0.
Image is loaded on some places, but for one of our widget the image failed to load. I have added below the widget example and the stack trace from the error.
This is because we update UI component on background thread, the only workaround is making all ui change inside OnResourceReady to run in UI thread. Do you know any better ways to do this ?

Let me know if you need additional information.

Glide Version: 4.9.0


Integration libraries: using glide transformer library version 3.3.0

Device/Android Version: Android version 8 and 6, Asus & samsung all catching error.

Code example where error happen:

Glide.with(mContext)
                .load(mImageUrl[position])
                .apply(new RequestOptions().onlyRetrieveFromCache(true))
                .transition(DrawableTransitionOptions.withCrossFade())
                .error(Glide.with(mContext).load(mImageUrl[position]).listener(new RequestListener<Drawable>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                        long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);

                        ImageWidget.setNormal();
                        TouchImageView.setImageDrawable(resource);
                        TouchImageView.setVisibility(View.VISIBLE);

                        width[position] = resource.getIntrinsicWidth();
                        height[position] = resource.getIntrinsicHeight();


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

                    @Override
                    public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                        ImageWidget.setNormal();
                        TouchImageView.setImageDrawable(resource);
                        TouchImageView.setVisibility(View.VISIBLE);

                        width[position] = resource.getIntrinsicWidth();
                        height[position] = resource.getIntrinsicHeight();
                        return false;
                    }
                }).submit();

Stack trace / LogCat:
E/GlideExecutor: Request threw uncaught throwable com.bumptech.glide.load.engine.CallbackException: Unexpected exception thrown by non-Glide code at com.bumptech.glide.load.engine.EngineJob.callCallbackOnResourceReady(EngineJob.java:154) at com.bumptech.glide.load.engine.EngineJob$CallResourceReady.run(EngineJob.java:398) at com.bumptech.glide.util.Executors$2.execute(Executors.java:30) at com.bumptech.glide.load.engine.EngineJob.notifyCallbacksOfResult(EngineJob.java:250) at com.bumptech.glide.load.engine.EngineJob.onResourceReady(EngineJob.java:304) at com.bumptech.glide.load.engine.DecodeJob.notifyComplete(DecodeJob.java:336) at com.bumptech.glide.load.engine.DecodeJob.notifyEncodeAndRelease(DecodeJob.java:442) at com.bumptech.glide.load.engine.DecodeJob.decodeFromRetrievedData(DecodeJob.java:424) at com.bumptech.glide.load.engine.DecodeJob.onDataFetcherReady(DecodeJob.java:387) at com.bumptech.glide.load.engine.DataCacheGenerator.onDataReady(DataCacheGenerator.java:95) at com.bumptech.glide.load.model.ByteBufferFileLoader$ByteBufferFetcher.loadData(ByteBufferFileLoader.java:74) at com.bumptech.glide.load.engine.DataCacheGenerator.startNext(DataCacheGenerator.java:75) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:309) at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:276) at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:235) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:764) at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:446) Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7753) at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1225) at android.view.View.requestLayout(View.java:23093) at android.view.View.requestLayout(View.java:23093) at android.view.View.requestLayout(View.java:23093) at android.view.View.requestLayout(View.java:23093) at android.view.View.requestLayout(View.java:23093) at android.view.View.requestLayout(View.java:23093) at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:360) at android.view.View.requestLayout(View.java:23093) at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:360) at android.view.View.requestLayout(View.java:23093) at android.view.View.requestLayout(View.java:23093) at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:360) at android.view.View.requestLayout(View.java:23093) at android.view.View.setFlags(View.java:14102) at android.view.View.setVisibility(View.java:9992) at com.myapp.android.view.widget.LoadingWidget.setNormal(LoadingWidget.java:114) at com.myapp.android.view.adapter.ImageFullScreenPagerAdapter$1.onResourceReady(ImageFullScreenPagerAdapter.java:128) at com.myapp.android.view.adapter.ImageFullScreenPagerAdapter$1.onResourceReady(ImageFullScreenPagerAdapter.java:120) at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:572) at com.bumptech.glide.request.SingleRequest.onResourceReady(SingleRequest.java:544) at com.bumptech.glide.load.engine.EngineJob.callCallbackOnResourceReady(EngineJob.java:152) at com.bumptech.glide.load.engine.EngineJob$CallResourceReady.run(EngineJob.java:398) at com.bumptech.glide.util.Executors$2.execute(Executors.java:30) at com.bumptech.glide.load.engine.EngineJob.notifyCallbacksOfResult(EngineJob.java:250) at com.bumptech.glide.load.engine.EngineJob.onResourceReady(EngineJob.java:304) at com.bumptech.glide.load.engine.DecodeJob.notifyComplete(DecodeJob.java:336) at com.bumptech.glide.load.engine.DecodeJob.notifyEncodeAndRelease(DecodeJob.java:442) at com.bumptech.glide.load.engine.DecodeJob.decodeFromRetrievedData(DecodeJob.java:424) at com.bumptech.glide.load.engine.DecodeJob.onDataFetcherReady(DecodeJob.java:387) at com.bumptech.glide.load.engine.DataCacheGenerator.onDataReady(DataCacheGenerator.java:95) at com.bumptech.glide.load.model.ByteBufferFileLoader$ByteBufferFetcher.loadData(ByteBufferFileLoader.java:74) at com.bumptech.glide.load.engine.DataCacheGenerator.startNext(DataCacheGenerator.java:75) at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:309) at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:276) at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:235) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:764) at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:446)

stale

Most helpful comment

Use a Target instead of a RequestListener to set your image which in turn will avoid using submit() to load data into views or items on the UI thread.

All 7 comments

This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.

Use a Target instead of a RequestListener to set your image which in turn will avoid using submit() to load data into views or items on the UI thread.

This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.

Thanks for reply, can we have warning or error on android studio for this ? I guess it is easy for someone to have a bug if dont know about it.

I'm not able to add warnings or errors to Android Studio unfortunately. What made you decide to use RequestListener instead of Target? If there's some documentation we could correct or clarify I'd be happy to do so.

This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.

Thanks @sjudd, we already change our implementation to Target. Appreciate your help.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

r4m1n picture r4m1n  路  3Comments

FooBarBacon picture FooBarBacon  路  3Comments

ghost picture ghost  路  3Comments

Tryking picture Tryking  路  3Comments

Morteza-Rastgoo picture Morteza-Rastgoo  路  3Comments