I am using glide to extract a bitmap from the cache and save it elsewhere. The relevant function below (based on this post:) fails to trigger the extraction. In fact, the log line 'Log.d(TAG, "About to start extraction");' below never gets triggered.
Any ideas on why the simple target function never gets called?
public byte[] extractImageFromCache(Context context, String pictureURL) {
byte[] byteArray = new byte[0];
if (context != null && pictureURL != null && !pictureURL.isEmpty()) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Glide.with(context)
.load(pictureURL)
.asBitmap()
.toBytes()
.diskCacheStrategy(DiskCacheStrategy.SOURCE) // Load the original hires image
.into(new SimpleTarget<byte[]>() {
@Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
Log.d(TAG, "About to start extraction");
new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
Log.d(TAG, "Start extraction");
try {
Log.d(TAG, "Image bytes len: " + resource.length);
byteArrayOutputStream.write(resource);
byteArrayOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "Unable to load image: " + pictureURL);
e.printStackTrace();
}
return null;
}
}.execute();
}
});
Log.d(TAG, String.format("Got image bytes: %d for %s", byteArrayOutputStream.size(), pictureURL));
return byteArrayOutputStream.toByteArray();
}
return null;
}
Glide is an Image Loader Library for Android developed by bumptech and is a library that is recommended by Google. It has been used in many Google open source projects including Google I/O 2014 official application. It provides animated GIF support and handles image loading/caching.
To simply load an image to LinearLayout, we call the with() method of Glide class and pass the context, then we call the load() method, which contains the URL of the image to be downloaded and finally we call the into() method to display the downloaded image on our ImageView.
Google creates a separate link for each image which can be copied-and-pasted into your Glide app spreadsheet. The image picker is pretty basic. Images are stored in Firebase and limited to 10mb files.
Glide knows the dimension of the imageView as it takes the imageView as a parameter. Glide down-samples the image without loading the whole image into the memory. This way, the bitmap takes less memory, and the out of memory error is solved.
As you have mentioned, Log.d(TAG, "About to start extraction") never gets triggered, which means onResourceReady never gets called. This could happen due to some error. Try overriding error callbacks.
To identify the problem I would recommend you to override other callbacks of SimpleTarget to debug the problem.
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
// load has been cleared
}
@Override
public void onLoadStarted(@Nullable Drawable placeholder) {
// load has started
}
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
// load failed due to some reason, notify callers here about the same
}
By using SimpleTarget object we can easily get Bitmap we are trying to extract from cache or network since by default glide look for cache hit.
Modify your Glide loading code to this :
Glide.with(this)
.load("https://cdn-images-1.medium.com/max/1200/1*hcfIq_37pabmAOnw3rhvGA.png")
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Log.d("Size ", "width :"+resource.getWidth() + " height :"+resource.getHeight());
imageView.setImageBitmap(resource);
storeImage(resource);
}
});
And Using this or any other mechanism for storing bitmap to external/internal storage.
private void storeImage(Bitmap image) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
Log.d(TAG,
"Error creating media file, check storage permissions: ");// e.getMessage());
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
image.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.close();
Log.d(TAG, "img dir: " + pictureFile);
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
private File getOutputMediaFile(){
// To be safe, you should check that the SDCard is mounted
// using Environment.getExternalStorageState() before doing this.
File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
+ "/Android/data/"
+ getApplicationContext().getPackageName()
+ "/Files");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
return null;
}
}
File mediaFile;
Random generator = new Random();
int n = 1000;
n = generator.nextInt(n);
String mImageName = "Image-"+ n +".jpg";
mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);
return mediaFile;
}
I am using Glide ver 3.7
compile "com.github.bumptech.glide:glide:3.7.0"
Here is full working example : https://github.com/nieldeokar/GlideApp
First of all, your return is invalid because Glide executes the request in an asynchronous thread. So byteArrayOutputStream
is never populated in time before the function returns. This means your function will always return an empty byte array. This also means your log statement Log.d(TAG, String.format("Got image bytes: %d for %s", byteArrayOutputStream.size(), pictureURL));
will be invalid. Knowing this, your About to start extraction
will show up after Got image bytes...
. You will need to reformat your code to use callbacks to notify the caller of the function that your code has retrieved the array. Something like this:
public interface GlideByteLoadCallback {
void onBytesExtracted(byte[] bytes);
void onFail(String message);
}
public void extractImageFromCache(Context context, String pictureURL, GlideByteLoadCallback callback) {
if (context != null && pictureURL != null && !pictureURL.isEmpty()) {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Glide.with(context)
.load(pictureURL)
.asBitmap()
.toBytes()
.diskCacheStrategy(DiskCacheStrategy.SOURCE) // Load the original hires image
.into(new SimpleTarget<byte[]>() {
@Override public void onResourceReady(final byte[] resource, GlideAnimation<? super byte[]> glideAnimation) {
Log.d(TAG, "About to start extraction");
new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
Log.d(TAG, "Start extraction");
try {
Log.d(TAG, "Image bytes len: " + resource.length);
byteArrayOutputStream.write(resource);
byteArrayOutputStream.flush();
if (callback != null) callback.onBytesExtracted(byteArrayOutputStream.toByteArray());
} catch (IOException e) {
e.printStackTrace();
Log.i(TAG, "Unable to load image: " + pictureURL);
e.printStackTrace();
if (callback != null) callback.onFail("Extraction failed");
}
}
}.execute();
}
});
}
if (callback != null) callback.onFail("Invalid url");
}
Then call it with:
extractImageFromCache(context, picture, new GlideByteLoadCallback() {
@Override
public void onFail(String message) {
// handle failure here
}
@Override
public void onBytesExtracted(byte[] bytes) {
// do stuff with bytes here
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With