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

CalledFromWrongThreadException when load from cache #4457

Open sunytan opened 3 years ago

sunytan commented 3 years ago

Glide Version:4.10.0

Integration libraries:3.12.6

Device/Android Version:SLA-AL00;Android 7.0,level 24

Issue details / Repro steps / Use case background:

className: Engine.java

  public <R> LoadStatus load(
      GlideContext glideContext,
      Object model,
      Key signature,
      int width,
      int height,
      Class<?> resourceClass,
      Class<R> transcodeClass,
      Priority priority,
      DiskCacheStrategy diskCacheStrategy,
      Map<Class<?>, Transformation<?>> transformations,
      boolean isTransformationRequired,
      boolean isScaleOnlyOrNoTransform,
      Options options,
      boolean isMemoryCacheable,
      boolean useUnlimitedSourceExecutorPool,
      boolean useAnimationPool,
      boolean onlyRetrieveFromCache,
      ResourceCallback cb,
      Executor callbackExecutor) {
    long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;

    ...

    // Avoid calling back while holding the engine lock, doing so makes it easier for callers to
    // deadlock.
    cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
    return null;
  }

when memoryResource not null , why not call onResourceReady with callbackExecutor. it cause CalledFromWrongThreadException

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

call glide.with in sub thread

Glide.with(mParent).asDrawable()
                            .apply(diskCacheStrategyOf(DiskCacheStrategy.AUTOMATIC))
                            .load(Uri.parse(url))
                            .into(new CustomTarget<Drawable>() {
                                @Override
                                public void onResourceReady(@NonNull Drawable drawable,
                                        @Nullable Transition<? super Drawable>
                                                transition) {
                                   ...
                                            imageView.setVisibility(View.VISIBLE);
                                            imageView.setImageDrawable(drawable);
                                    ...
                                }

                                @Override
                                public void onLoadCleared(@Nullable Drawable placeholder) {
...
                                }

                            });

Layout XML:

<FrameLayout xmlns:android="...

Stack trace / LogCat:

android.view.ViewRootImpl$CalledFromWrongThreadException: (Pv_none;Activity_xxxActivity)Only the original thread that created a view hierarchy can touch its views.
android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7377)
android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1197)
android.view.ViewGroup.invalidateChild(ViewGroup.java:5261)
android.view.View.invalidateInternal(View.java:13721)
android.view.View.invalidate(View.java:13656)
android.view.View.setFlags(View.java:11550)
android.view.View.setVisibility(View.java:8046)
com.tencent.xxx.ui.main.more.b.b$4.a(xxx.java:518)
com.tencent.xxx.ui.main.more.b.b$4.a(xxx.java:503)
com.bumptech.glide.e.j.a(SingleRequest.java:624)
com.bumptech.glide.e.j.a(SingleRequest.java:568)
com.bumptech.glide.load.b.k.a(Engine.java:220)
com.bumptech.glide.e.j.a(SingleRequest.java:442)
com.bumptech.glide.e.a.c.a(CustomTarget.java:107)
com.bumptech.glide.e.j.a(SingleRequest.java:251)
com.bumptech.glide.c.n.a(RequestTracker.java:43)
com.bumptech.glide.l.a(RequestManager.java:674)
com.bumptech.glide.k.a(RequestBuilder.java:641)
com.bumptech.glide.k.a(RequestBuilder.java:608)
com.bumptech.glide.k.a(RequestBuilder.java:599)
com.tencent.xx.ui.main.more.b.b.q(xxx.java:503)
com.tencent.xxx.ui.main.more.b.b.lambda$jo94G-l7iggA1ATn1PuxLJ4Dh8k(xxx.java)
com.tencent.xxx.ui.main.more.b.-$$Lambda$b$jo94G-l7iggA1ATn1PuxLJ4Dh8k.run(lambda)
com.tencent.xxx.util.e.h$a.run(CustomThreadPool.java:1154)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
java.lang.Thread.run(Thread.java:776)
sjudd commented 3 years ago

It's a little more complicated than just using the callback executor because we don't want to post to the UI thread if we're loading an image into a View on the main thread. Doing so would add an unnecessary delay and lead to blinking images.

I see your point though, that we should be consistent about using the callback executor.

We could probably update the mainThreadExecutor to just execute directly if we're on the main thread. It's a bit weird either way.

sunytan commented 3 years ago

Thank you for your reply