Reputation: 5673
I need to transform image during loading by Glide
.
Inside transform()
method I also need to load another image and draw it over current image. So I also use Glide
for load task inside transform()
. I use blocking method get()
because I need to get result instantly and transform()
operates not in the main thread which is good.
It is very important to note that code loads several images at the same time and all images should be transformed, so all processes of transformation include loading of additional image by Glide
.
My problem is when I use Glide
to load image inside transform()
method in parallel several times in a row - it blocks code and does not continue work.
Here is the code:
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;
}
}
What I see in console output:
D/com.golovin.androidtest.MainActivity: Before load. Thread fifo-pool-thread-0 D/com.golovin.androidtest.MainActivity: Before load. Thread fifo-pool-thread-1
That's all. Glide
does not continue a work and I see nothing. By the way if I use get(2, TimeUnit.SECONDS)
instead of get()
Glide
will throw TimeoutException
.
What do I do wrong?
Upvotes: 0
Views: 3196
Reputation: 46480
You're blocking Glide by requesting a new image. I guess that's obvious, here's why:
.into(new SimpleTarget<Bitmap>...)
schedules 5 new loads: 1, 2, 3, 4, 5fifo-pool
(you likely have two cores).into(20, 20)
which schedules 2 more loads: 6, 7.get()
blocks while those two are completedThe problem is that for load 6 and 7 to complete Glide first has to complete the first 5 out of which 1 and 2 are in progress, but the two in-progress ones require the 6 and 7 to complete -> cycle.
You just simply cannot block Glide's threads with a Glide load, try to flip the order:
....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
}
}
});
You can fire up your own executor service and schedule background tasks that look like this:
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
You can simply load both Bitmaps in the sync way and combine them within the task without a Glide transformation. You can access the pool from Glide.get(context).getBitmapPool()
if you want to reuse some Bitmaps.
Keep in mind that it may not worth all this extra complexity, consider using a layout to position one ImageView on top of another (with a FrameLayout
for example) and load as ususal.
Solution 1 is more convenient than Solution 2 and 3, because you already have the icon
when you start the other loads and you're on the UI thread, so you can apply the transformation and Glide will deliver the images to the ImageView (if any).
Upvotes: 4