Android加载自动下载型URL图片遇阻:Picasso/Glide无法处理该类链接
解决Android中Picasso/Glide无法加载自动下载型图片URL的问题
我之前也踩过一模一样的坑!这种自动触发下载的URL,核心问题是服务器返回的响应头里带了Content-Disposition: attachment,而Picasso和Glide默认会把这类响应当成“需要下载的文件”,而非直接可展示的图片资源(正常图片响应头一般是Content-Disposition: inline),所以才会加载失败。
下面给你两种库的具体解决办法:
针对Picasso的解决方案
你需要自定义一个OkHttpDownloader,拦截响应并强制处理成可展示的图片:
public class CustomPicassoDownloader extends OkHttp3Downloader { public CustomPicassoDownloader(Context context) { super(context); } public CustomPicassoDownloader(OkHttpClient client) { super(client); } @Override public Response load(Uri uri, int networkPolicy) throws IOException { Response originalResponse = super.load(uri, networkPolicy); // 忽略Content-Disposition的attachment标记,强制返回图片流 return originalResponse.newBuilder() .header("Content-Disposition", "inline") .build(); } }
然后在初始化Picasso的时候替换默认下载器:
OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); Picasso picasso = new Picasso.Builder(context) .downloader(new CustomPicassoDownloader(okHttpClient)) .build(); Picasso.setSingletonInstance(picasso);
之后再用Picasso加载目标链接就正常了。
针对Glide的解决方案
Glide可以通过自定义OkHttpUrlLoader来处理这类响应:
首先创建一个自定义的OkHttpStreamFetcher,修改响应处理逻辑:
public class CustomOkHttpStreamFetcher implements DataFetcher<InputStream> { private final OkHttpClient client; private final GlideUrl url; private InputStream stream; private Response response; public CustomOkHttpStreamFetcher(OkHttpClient client, GlideUrl url) { this.client = client; this.url = url; } @Override public void loadData(Priority priority, DataCallback<? super InputStream> callback) { Request.Builder requestBuilder = new Request.Builder().url(url.toStringUrl()); for (Map.Entry<String, String> headerEntry : url.getHeaders().entrySet()) { String key = headerEntry.getKey(); requestBuilder.addHeader(key, headerEntry.getValue()); } Request request = requestBuilder.build(); try { response = client.newCall(request).execute(); // 强制把attachment改成inline,让Glide识别为可展示的图片 Response modifiedResponse = response.newBuilder() .header("Content-Disposition", "inline") .build(); stream = modifiedResponse.body().byteStream(); callback.onDataReady(stream); } catch (IOException e) { callback.onLoadFailed(e); } } @Override public void cleanup() { try { if (stream != null) { stream.close(); } if (response != null) { response.body().close(); } } catch (IOException e) { e.printStackTrace(); } } @Override public void cancel() {} @Override public Class<InputStream> getDataClass() { return InputStream.class; } @Override public DataSource getDataSource() { return DataSource.REMOTE; } }
然后创建自定义的OkHttpUrlLoader:
public class CustomOkHttpUrlLoader implements ModelLoader<GlideUrl, InputStream> { private final OkHttpClient client; public CustomOkHttpUrlLoader(OkHttpClient client) { this.client = client; } @Override public LoadData<InputStream> buildLoadData(GlideUrl model, int width, int height, Options options) { return new LoadData<>(new ObjectKey(model), new CustomOkHttpStreamFetcher(client, model)); } @Override public boolean handles(GlideUrl model) { return true; } public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> { private static volatile OkHttpClient internalClient; private final OkHttpClient client; public Factory() { this(getInternalClient()); } public Factory(OkHttpClient client) { this.client = client; } private static OkHttpClient getInternalClient() { if (internalClient == null) { synchronized (Factory.class) { if (internalClient == null) { internalClient = new OkHttpClient.Builder().build(); } } } return internalClient; } @Override public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) { return new CustomOkHttpUrlLoader(client); } @Override public void teardown() {} } }
最后在Glide的配置类里注册这个Loader:
@GlideModule public class MyGlideModule extends AppGlideModule { @Override public void registerComponents(Context context, Glide glide, Registry registry) { OkHttpClient client = new OkHttpClient.Builder().build(); registry.replace(GlideUrl.class, InputStream.class, new CustomOkHttpUrlLoader.Factory(client)); } }
这样配置后Glide就能正常加载这类自动下载的图片链接了。
本质上就是通过修改响应头,让图片库认为这是一个可以直接展示的内嵌资源,而不是需要下载的附件。
内容的提问来源于stack exchange,提问作者George Radu
相关产品推荐
相关产品推荐

