Hi,
I have switched my current project from Picasso to Glide. However, I cannot manage to load an image from the application assets. Is that even possible?
Sample code:
String assetPath = "file:///android_asset/flags/FR.jpg";
Glide.with(getContext())
.load(Uri.parse(assetPath))
.placeholder(missingFlagDrawable)
.centerCrop()
.crossFade()
.into(flag);
I have also tried the load(String) method without success and I don't see a load method taking for instance an InputStream or a FileDescriptor I could have obtained with the AssetManager class.
That exact same code was working in Picasso.
Glide is working properly in the rest of the app and loading nicely remote images.
Thanks for reporting this, in theory the Uri is sufficient. What failure do you see (if you don't see any exception you can turn on logging using adb shell setprop log.tag.GenericRequest, see https://github.com/bumptech/glide/wiki/Debugging-and-Error-Handling)?
If using the AssetManager is a requirement you can always define a custom ModelLoader that uses the AssetManager to return an InputStream and pass it in to your request with the using() syntax:
Glide.with(yourFragment)
.using(yourCustomModelLoader)
.load(Uri.parse(assetPath))
...
If we need to use the AssetManager to parse these urls rather than just relying on a ContentResolver, the best fix for the library would be to modify the existing UriLoader and adding another case if we're given an asset Uri.
I get this exception thrown:
09-24 17:58:12.790 22860-22860/com.example D/GenericRequest﹕ load failed
java.io.FileNotFoundException: No such file or directory
at android.os.Parcel.openFileDescriptor(Native Method)
at android.os.ParcelFileDescriptor.openInternal(ParcelFileDescriptor.java:252)
at android.os.ParcelFileDescriptor.open(ParcelFileDescriptor.java:198)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:899)
at android.content.ContentResolver.openAssetFileDescriptor(ContentResolver.java:831)
at com.bumptech.glide.load.data.FileDescriptorLocalUriFetcher.loadResource(FileDescriptorLocalUriFetcher.java:20)
at com.bumptech.glide.load.data.FileDescriptorLocalUriFetcher.loadResource(FileDescriptorLocalUriFetcher.java:13)
at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:49)
at com.bumptech.glide.load.data.LocalUriFetcher.loadData(LocalUriFetcher.java:21)
at com.bumptech.glide.load.model.ImageVideoModelLoader$ImageVideoFetcher.loadData(ImageVideoModelLoader.java:82)
at com.bumptech.glide.load.model.ImageVideoModelLoader$ImageVideoFetcher.loadData(ImageVideoModelLoader.java:52)
at com.bumptech.glide.load.engine.SourceResourceRunner.decodeFromSource(SourceResourceRunner.java:178)
at com.bumptech.glide.load.engine.SourceResourceRunner.runWrapped(SourceResourceRunner.java:144)
at com.bumptech.glide.load.engine.SourceResourceRunner.run(SourceResourceRunner.java:123)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
at com.bumptech.glide.load.engine.executor.FifoPriorityThreadPoolExecutor$DefaultThreadFactory$1.run(FifoPriorityThreadPoolExecutor.java:52)
However the file does exist in the asset folder. By using a custom loader/fetcher, I manage to load those files properly. Here are the corresponding classes: https://gist.github.com/vpratfr/5e61fd452a27e964ea63
Then I am loading the assets with:
Glide.with(getContext())
.using(new AssetUriLoader(getContext()))
.load(Uri.parse(flagAsset.get()))
So something is wrong with the default loading, I don't know if that's a bug on your side or on mine.
One problem remains : inside a GridView (probably in a ListView too), I cannot see the image without scrolling the view out of sight and getting it back on screen. Does it have something to do with caching? Or with my custom loader/fetcher?
Thanks for the code and report I'm looking into asset manager uris.
I'm not sure where to point you to with regards to the GridView issue. Glide's Flickr sample app uses grid views without a problem. The only problem I see in your code is that you don't need to use a weak reference for a Context in your DataFetcher. Instead just pass in the application Context (context.getApplicationContext()). That said, I don't think using a weak reference would cause the image to fail to load.
Do you see a debug log when the image fails to load the first time? What width and height do your views have?
image.setImageBitmap(BitmapFactory.decodeStream(getAssets().open("test.jpg")));
image.setImageURI(Uri.parse("file:///android_asset/test.jpg"));
it gives the following messages:
java.io.FileNotFoundException: /android_asset/test.jpg: open failed: ENOENT (No such file or directory)
resolveUri failed on bad bitmap uri: file:///android_asset/test.jpg
and it is because ContentResolver doesn't support android_asset Uris (see openInputStream and openAssetFileDescriptor): https://code.google.com/p/android/issues/detail?id=42675
we want the following to work (which is roughly equivalent to the above setImageURI version):
Glide.with(this).load("file:///android_asset/test.jpg").into(image);
java.io.FileNotFoundException: No such file or directory
It fails because Glide doesn't handle the android_asset "folder":
https://github.com/bumptech/glide/blob/v3.3.1/library/src/main/java/com/bumptech/glide/load/model/UriLoader.java#L29
compare that to:
late AssetBitmapHunter which is now AssetRequestHandler
Add if to UriLoader for checking "root folder" android_asset and implement an AssetFetcher like @vpratfr did; however I think relativePath.replace("file:///android_asset/", ""); should be outside of the class in UriLoader, because there is no such thing as an "asset Uri" in the Android framework, assets are referenced by relative path to the assets folder.
As for the GridView, it really depends on how you declared the ImageView in XML and what methods you call on them. Aside @sjudd's suggestions you can try adding a .listener() and log/debug whether the Bitmap arrives at the target when it's not shown.
I agree that these kind of Uris should be supported for ease of use, but why don't you put your images into raw or drawable-nodpi, or even simpler: use drawables?
Hi,
Currently doing some other tasks, will try to debug the GridView in the afternoon. Thanks for having had a look at it.
I think too the right thing to do would be to add an additional if statement in the UriLoader class to detect assets and use an appropriate Fetcher.
I have not directly implemented it in the library and submitted a PR because I still have not taken the time to understand the Model things and would not want to break something (and honestly don't have much because my client is pushing). From the code I sent I think that should be an easy fix though.
I agree that these kind of Uris should be supported for ease of use, but why don't you put your images into raw or drawable-nodpi, or even simpler: use drawables?
Because the file name is dynamically determined. Those are flags and I get the country list from a webservice. The flag name is taken from the ISO code (for instance FR.png).
If I was using a resource, that name would get compiled to an int (R.raw.FR) and I would need some reflection magic (or an ugly switch statement) to link the ISO code to the flag resource.
Hence the asset is required in my case.
If I was using a resource, that name would get compiled to an int (R.raw.FR) and I would need some reflection magic (or an ugly switch statement) to link the ISO code to the flag resource.
... or you could use the method provided by the framework:
public static int getRawResourceID(Context context, String rawResourceName) {
return context.getResources().getIdentifier(rawResourceName, "raw", context.getPackageName());
}
public static int getDrawableResourceID(Context context, String drawableResourceName) {
return context.getResources().getIdentifier(drawableResourceName, "drawable", context.getPackageName());
}
I'm doing the same, I have a DB table for categories and the icon name is stored there (I'm loading SVG files from raw this way via Glide). Also "ugly switch" usually converts nicely to lookup Map.
_Or_ if you really want to pass Uri around:
android.resource://[package]/[res type]/[res name]
android.resource://com.your.employer/drawable/ic_launcher
This even works if you put it in XML (android:src), because ContentResolver/Android framework supports this. I think the above uses the same method I laid out above, but also involves parsing the Uri first.
Ok. Back with some tests. I have implemented SVG support (using your sample as a base) and I am now using the method you describe (SVGs in the raw resource folder and some low-res versions in the drawable resource folder).
More info about the GridView bug:
SVGs get properly loaded in that view. Drawables however are only loaded when the GridView row is out of sight and back (using an adapter and following the ViewHolder pattern).
Glide.with... code changed to the similar Picasso.with... code, all the rest is the same.So my conclusion : Picasso is doing something different than Glide when it comes to setting a drawable.
My first guess : it may be related to an issue logged in the RoundedImageView repo if you are using the setImageURI method and Picasso is using another method (like directly calling setImageResource). This would explain too why SVGs get shown properly as they are not using the setImageURI method but probably setImageDrawable instead.
What api level are you using? Not 4.0.4 by any chance?
If you use Glide.with(xxx).load(xxx).asBitmap() does it work as you expect?
Glide uses setImageDrawable, not setImageUri. Using asBitmap() will cause it to use setImageBitmap instead.
Thanks for looking more into this!
ANDROID_BUILD_MIN_SDK_VERSION=15
ANDROID_BUILD_TARGET_SDK_VERSION=20
Testing on Android 4.4.4 (Galaxy Note 2 with Slimkat ROM)
It works when using asBistmap
Any chance you could add a bit of code or a sample project demonstrating the issue? Even just the xml you're using to specify your grid and the items in it would be helpful.
As I mentioned earlier I know the drawables can work in a GridView because the Flickr sample works fine, but clearly something is a bit different here.
Thanks for the follow up.
I spent a little while looking in to this, it seems like RoundedImageView doesn't handle TransitionDrawables quite right. Removing the crossfade using dontAnimate() or using a normal fade in solved the problem. Using asBitmap() will also work because Glide doesn't allow you to cross fade bitmaps.
I think the ideal solution is to follow the pattern the author setup for Picasso and create your own custom Glide transformation: https://github.com/vinc3m1/RoundedImageView/blob/master/roundedimageview/src/main/java/com/makeramen/RoundedTransformationBuilder.java.
I'll leave this open to track the asset manager uris, but otherwise everything seems WAI from Glide's point of view.
Hi,
We are updating image but does not change file path. In this case, glide does not refresh image.
Please tell me how to resolve this issue.
Thanks in advance.
@androiddeveloperPooja30 Check out the wiki on cache invalidation: https://github.com/bumptech/glide/wiki/Caching-and-Cache-Invalidation#custom-cache-invalidation. You will want to pass in a new signature each time you update the file.
Most helpful comment
As it should be loaded
As @vpratfr wants to load it
it gives the following messages:
and it is because
ContentResolverdoesn't supportandroid_assetUris (seeopenInputStreamandopenAssetFileDescriptor): https://code.google.com/p/android/issues/detail?id=42675Why Picasso works
we want the following to work (which is roughly equivalent to the above
setImageURIversion):It fails because Glide doesn't handle the
android_asset"folder":https://github.com/bumptech/glide/blob/v3.3.1/library/src/main/java/com/bumptech/glide/load/model/UriLoader.java#L29
compare that to:
late
AssetBitmapHunterwhich is nowAssetRequestHandlerSolution
Add
iftoUriLoaderfor checking "root folder"android_assetand implement anAssetFetcherlike @vpratfr did; however I thinkrelativePath.replace("file:///android_asset/", "");should be outside of the class inUriLoader, because there is no such thing as an "asset Uri" in the Android framework, assets are referenced by relative path to theassetsfolder.Other comments
As for the
GridView, it really depends on how you declared theImageViewin XML and what methods you call on them. Aside @sjudd's suggestions you can try adding a.listener()and log/debug whether theBitmaparrives at the target when it's not shown.I agree that these kind of Uris should be supported for ease of use, but why don't you put your images into
rawordrawable-nodpi, or even simpler: use drawables?