尝试在 transform() 中加载图像时 Glide 冻结

Glide freezes when trying to load image inside transform()

我需要在 Glide 加载期间转换图像。

transform() 方法中,我还需要加载另一个图像并将其绘制在当前图像上。所以我也在 transform() 中使用 Glide 来加载任务。我使用阻塞方法 get() 因为我需要立即获得结果并且 transform() 不在主线程中运行,这很好。

需要注意的是,代码同时加载多张图片,所有图片都要进行转换,所以所有转换过程都包括通过Glide加载额外的图片。

我的问题是,当我连续多次使用 Glidetransform() 方法中并行加载图像时 - 它会阻塞代码并且无法继续工作。

代码如下:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    for (int i = 0; i < 5; i++) {

        final int a = i;

        Glide.with(this)
                .fromResource()
                .asBitmap()
                .load(R.drawable.ic_non_provisioned)
                .transform(new BitmapTransformation(this) {
                    @Override
                    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {

                        Log.d(MainActivity.class.getName(), String.format("Before load. Thread %s",
                                Thread.currentThread().getName()));

                        Bitmap bitmap = load(); // freezes here

                        Log.d(MainActivity.class.getName(), "After load");


                        return toTransform;
                    }

                    @Override
                    public String getId() {
                        return String.valueOf(a); // important for demo of bug
                    }
                })
                .into(new SimpleTarget<Bitmap>() {
                    @Override
                    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
                        Log.d(MainActivity.class.getName(), "Load finished");
                    }
                });
        }
}

private Bitmap load() {
    try {
        return Glide.with(this)
                .fromResource()
                .asBitmap()
                .load(R.drawable.ic_search)
                .into(20, 20)
                .get(); // freezes here
    } catch (Exception e) {
        return null;
    }
}

我在控制台输出中看到的内容:

D/com.golovin.androidtest.MainActivity: Before load. Thread fifo-pool-thread-0 D/com.golovin.androidtest.MainActivity: Before load. Thread fifo-pool-thread-1

就是这样。 Glide 没有继续工作,我什么也没看到。顺便说一下,如果我使用 get(2, TimeUnit.SECONDS) 而不是 get() Glide 将抛出 TimeoutException.

我做错了什么?

您正在通过请求新图像来阻止 Glide。我想这很明显,原因如下:

  • .into(new SimpleTarget<Bitmap>...) 计划 5 个新负载:1、2、3、4、5
  • 其中 2 个开始于 fifo-pool(您可能有两个核心)
  • 位图已加载并传递给您的转换
  • 这两个转换调用 .into(20, 20) 调度另外 2 个负载:6、7
  • .get() 块,同时完成这两个

问题是要完成加载 6 和 7,Glide 首先必须完成前 5 个,其中 1 和 2 正在进行中,但是两个正在进行的需要 6 和 7 才能完成 ->循环。

解决方案 1

你就是不能用Glide load阻塞Glide的线程,试试翻转顺序:

....load(R.drawable.ic_search).into(new SimpleTarget(20, 20) {
    @Override public void onResourceReady(Bitmap icon, GlideAnimation glideAnimation) {
        for (int i = 0; i < 5; i++) {
            // load others using icon passed into the transformation
        }
    }
});

解决方案 2

您可以启动自己的执行程序服务并安排后台任务,如下所示:

Bitmap icon = Glide.....load(R.drawable.ic_search).into(20, 20).get();
Bitmap result = Glide.....load(R.drawable.ic_non_provisioned).transform(using icon).into(Target.SIZE_ORIGINAL).get();
return result; // deliver to the UI thread somehow to be set in a view

解决方案 3

您可以简单地以同步方式加载两个位图,并在任务中将它们组合在一起,而无需 Glide 转换。如果您想重复使用一些位图,可以从 Glide.get(context).getBitmapPool() 访问池。

解决方案 4

请记住,所有这些额外的复杂性可能不值得,请考虑使用布局将一个 ImageView 放置在另一个 ImageView 之上(例如 FrameLayout)并照常加载。


方案一比方案二和方案三方便,因为你在启动其他加载时已经有了icon,而且你在UI线程上,所以你可以应用转换和 Glide 会将图像传送到 ImageView(如果有)。