Glide Version:
glide:4.10.0
Device/Android Version:
Fails on Nexus 5 API 23 emulator, Pixel 2 API 28 emulator, Samsung Galaxy TabA API 25 device.
Issue details / Repro steps / Use case background:
I am just using glide to load this placeholder image into a simple ImageView.
For some reason, this specific placeholder site causes a FileNotFound while other ones seem perfectly fine...
ex: "https://via.placeholder.com/600x400" does not work but "http://ipsumimage.appspot.com/600x400" does.
I also tried passing in a Uri using Uri.parse(urlString) and also tried encoding the url with Uri.encode(urlString) but both yielded the same result...
Note: I noticed on https://placeholder.com/rules/ if image usage is excessive, they will start 404ing your requests. I don't believe I have gone over their limit but is it possible that Glide is blocked?
Glide load line / GlideModule (if any) / list Adapter code (if any):
GlideApp.with(this)
.asBitmap()
.load("https://via.placeholder.com/600x400")
.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.into(imageView);
Layout XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image_view_parent"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false">
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="false">
</ImageView>
</RelativeLayout>
Stack trace / LogCat:
W/Glide: Load failed for https://via.placeholder.com/600x400 with size [-2147483648x-2147483648]
class com.bumptech.glide.load.engine.GlideException: Failed to load resource
There was 1 cause:
java.io.FileNotFoundException(https://via.placeholder.com/600x400)
call GlideException#logRootCauses(String) for more detail
Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetching data failed, class java.io.InputStream, REMOTE
There was 1 cause:
java.io.FileNotFoundException(https://via.placeholder.com/600x400)
call GlideException#logRootCauses(String) for more detail
Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Fetch failed
There was 1 cause:
java.io.FileNotFoundException(https://via.placeholder.com/600x400)
call GlideException#logRootCauses(String) for more detail
Cause (1 of 1): class java.io.FileNotFoundException: https://via.placeholder.com/600x400
I/Glide: Root cause (1 of 1)
java.io.FileNotFoundException: https://via.placeholder.com/600x400
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:238)
at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java)
at com.google.firebase.perf.network.zzd.getInputStream(com.google.firebase:firebase-perf@@19.0.4:58)
at com.google.firebase.perf.network.zze.getInputStream(com.google.firebase:firebase-perf@@19.0.4:11)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadDataWithRedirects(HttpUrlFetcher.java:102)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:56)
at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100)
at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.startNextOrFail(MultiModelLoader.java:164)
at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.onLoadFailed(MultiModelLoader.java:154)
at com.bumptech.glide.load.data.HttpUrlFetcher.loadData(HttpUrlFetcher.java:62)
at com.bumptech.glide.load.model.MultiModelLoader$MultiFetcher.loadData(MultiModelLoader.java:100)
at com.bumptech.glide.load.engine.SourceGenerator.startNext(SourceGenerator.java:63)
at com.bumptech.glide.load.engine.DecodeJob.runGenerators(DecodeJob.java:310)
at com.bumptech.glide.load.engine.DecodeJob.runWrapped(DecodeJob.java:279)
at com.bumptech.glide.load.engine.DecodeJob.run(DecodeJob.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
at com.bumptech.glide.load.engine.executor.GlideExecutor$DefaultThreadFactory$1.run(GlideExecutor.java:431)
Same problem here with version 4.11.0 on API 29 device
This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.
I got same issue and seems placeholder.com does something for Dalvik UA.
% curl -H 'User-Agent: Dalvik/2.1.0 (Linux; U; Android 10; Pixel 3 XL Build/QP1A.191005.007)' -H 'Host: via.placeholder.com' --compressed -I 'https://via.placeholder.com/100x100'
HTTP/1.1 410 Gone
...
# Changed UA to other than "Dalvik"
% curl -H 'User-Agent: Dalvic/2.1.0 (Linux; U; Android 10; Pixel 3 XL Build/QP1A.191005.007)' -H 'Host: via.placeholder.com' --compressed -I 'https://via.placeholder.com/100x100'
HTTP/1.1 200 OK
...
This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.
Same, is there a solution for this?
Same issue here, any solution?
Same here.
I am also facing the same issue with https://via.placeholder.com/
OS: Android 10 (API 29)
Glide Version: version 4.11.0
Is there anyone found the solution?
As @ytRino described, this issue is related to User-Agent header parameter. Then it;s not related to Glide, it's all about https://via.placeholder.com. There are several workarounds;
1 - Creating the URL by GlideUrl and adding User-Agent header.
GlideUrl url = new GlideUrl("https://your-url.com", new LazyHeaders.Builder()
.addHeader("User-Agent", "your-user-agent")
.build());
2 - If you are using AppGlideModule(), you can override OkHttpClient, then you can add an Interceptor to OkHttpClient to use your User-Agent header.
@Module
abstract class GlideBuilderModule {
companion object {
@Provides
@Singleton
fun providesOkHttpGlideModule(): OkHttpGlideModule {
return OkHttpGlideModule()
}
}
}
@Excludes(OkHttpLibraryGlideModule::class)
@GlideModule
class OkHttpGlideModule : AppGlideModule() {
@Inject
lateinit var okHttpClient: OkHttpClient
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
PostApplication.coreComponent.inject(this)
registry.replace(
GlideUrl::class.java,
InputStream::class.java,
OkHttpUrlLoader.Factory(okHttpClient)
)
}
}
@Module
abstract class NetworkModule {
companion object {
@Provides
@Singleton
fun providesOkHttpClient(userAgentInterceptor: UserAgentInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addInterceptor(userAgentInterceptor)
.build()
}
@Provides
@Singleton
fun providesOkHttpUserAgentInterceptor(context: Context): UserAgentInterceptor {
return UserAgentInterceptor(context)
}
}
}
class UserAgentInterceptor(private val context: Context) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest: Request = chain.request()
val requestWithUserAgent: Request = originalRequest.newBuilder()
.header("User-Agent", WebSettings.getDefaultUserAgent(context))
.build()
return chain.proceed(requestWithUserAgent)
}
}
As you can see from above example, I'm using WebSettings.getDefaultUserAgent(context) as User-Agent. I prefer this approach because in this way you'll use only one shared OkHttpClient between Retrofit and Glide.
Most helpful comment
As @ytRino described, this issue is related to User-Agent header parameter. Then it;s not related to Glide, it's all about https://via.placeholder.com. There are several workarounds;
1 - Creating the URL by GlideUrl and adding User-Agent header.
2 - If you are using AppGlideModule(), you can override OkHttpClient, then you can add an Interceptor to OkHttpClient to use your User-Agent header.
As you can see from above example, I'm using WebSettings.getDefaultUserAgent(context) as User-Agent. I prefer this approach because in this way you'll use only one shared OkHttpClient between Retrofit and Glide.