使用改造来下载图像文件

我在我的Android项目上使用了Retrofit 1.6.0,

请求url:

https://example.com/image/thumbs/filename/sample.png

我的界面是这样的:

public interface ImageService { @GET("/image/thumbs/filename/{filename}") @Streaming void getThumbs( @Path("filename") String filename, Callback<Response> callback ); } 

HTTP请求已成功,但出现了一些错误

 D/Retrofit(27613): ---> HTTP GET https://example.com/image/thumbs/filename/sample.png D/Retrofit(27613): ---> END HTTP (no body) D/Retrofit(27613): <--- HTTP 200 https://example.com/image/thumbs/filename/sample.png (451ms) D/Retrofit(27613): : HTTP/1.1 200 OK D/Retrofit(27613): Connection: Keep-Alive D/Retrofit(27613): Content-Disposition: inline; filename="sample.png" D/Retrofit(27613): Content-Type: image/png; charset=binary D/Retrofit(27613): Date: Wed, 11 Jun 2014 06:02:31 GMT D/Retrofit(27613): Keep-Alive: timeout=5, max=100 D/Retrofit(27613): OkHttp-Received-Millis: 1402466577134 D/Retrofit(27613): OkHttp-Response-Source: NETWORK 200 D/Retrofit(27613): OkHttp-Sent-Millis: 1402466577027 D/Retrofit(27613): Server: Apache/2.2.22 (Ubuntu) D/Retrofit(27613): Transfer-Encoding: chunked D/Retrofit(27613): X-Powered-By: PHP/5.4.28-1+deb.sury.org~precise+1 D/Retrofit(27613): ---- ERROR https://example.com/image/thumbs/filename/sample.png D/Retrofit(27613): java.io.UnsupportedEncodingException: binary D/Retrofit(27613): at java.nio.charset.Charset.forNameUEE(Charset.java:322) D/Retrofit(27613): at java.lang.String.<init>(String.java:228) D/Retrofit(27613): at retrofit.RestAdapter.logAndReplaceResponse(RestAdapter.java:478) D/Retrofit(27613): at retrofit.RestAdapter.access$500(RestAdapter.java:109) D/Retrofit(27613): at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:333) D/Retrofit(27613): at retrofit.RestAdapter$RestHandler.access$100(RestAdapter.java:220) D/Retrofit(27613): at retrofit.RestAdapter$RestHandler$2.obtainResponse(RestAdapter.java:278) D/Retrofit(27613): at retrofit.CallbackRunnable.run(CallbackRunnable.java:42) D/Retrofit(27613): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) D/Retrofit(27613): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) D/Retrofit(27613): at retrofit.Platform$Android$2$1.run(Platform.java:142) D/Retrofit(27613): at java.lang.Thread.run(Thread.java:841) D/Retrofit(27613): Caused by: java.nio.charset.UnsupportedCharsetException: binary D/Retrofit(27613): at java.nio.charset.Charset.forName(Charset.java:309) D/Retrofit(27613): at java.nio.charset.Charset.forNameUEE(Charset.java:320) D/Retrofit(27613): ... 11 more D/Retrofit(27613): ---- END ERROR 

我如何解决这个问题?

Solutions Collecting From Web of "使用改造来下载图像文件"

问题是响应中的内容types头包含伪造字符集:

 Content-Type: image/png; charset=binary 

改造看到这一点,并推断回应是它可以logging的文本。 您应该将问题报告给服务器的pipe理员。

如果您将问题报告给GitHub上的Retrofit的问题跟踪器,我们可能会从这个问题中恢复,而不是崩溃。

我正在使用rxjava进行改造,现在我有一个快速演示。 谈话很便宜,直接向你展示我的代码,希望它有帮助。

 public interface ImageService { String ENDPOINT = "HTTP://REPLACE.ME"; @GET @Streaming Observable<Bitmap> getThumbs(@Url String filepath); /******** * Helper class that sets up a new services *******/ class Instance { static ImageService instance; public static ImageService get() { if (instance == null) instance = newImageService(); return instance; } public static ImageService newImageService() { Retrofit retrofit = new Retrofit.Builder() .baseUrl(ImageService.ENDPOINT) .addConverterFactory(BitmapConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build(); return retrofit.create(ImageService.class); } } } 

而且我写了自己的BitmapConverterFactory将字节stream转换为位图:

 public final class BitmapConverterFactory extends Converter.Factory { public static BitmapConverterFactory create() { return new BitmapConverterFactory(); } private BitmapConverterFactory() { } @Override public Converter<ResponseBody, Bitmap> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { if (type == Bitmap.class) { return new Converter<ResponseBody, Bitmap>(){ @Override public Bitmap convert(ResponseBody value) throws IOException { return BitmapFactory.decodeStream(value.byteStream()); } }; } else { return null; } } @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { return null; } } 

Gradle依赖关系在这里:

 final RETROFIT_VERSION = '2.0.0-beta3' compile "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION" compile "com.squareup.retrofit2:adapter-rxjava:$RETROFIT_VERSION" 

欢呼声,vanvency

当然,我们通常使用毕加索加载图像,但有时我们确实需要使用Retrofit来加载一个特殊的图像(如获取validation码图像),您需要添加一些标题的请求,从响应头获得一些价值(当然,你可以也使用Picasso + OkHttp,但在一个项目中,您已经使用Retrofit来处理大多数的networking请求),所以在这里介绍如何通过Retrofit 2.0.0(我已经在我的项目中实现)来实现。

关键是您需要使用okhttp3.ResponseBody来接收响应,否则Retrofit会将响应数据parsing为JSON,而不是二进制数据。

代码:

 public interface Api { // don't need add 'Content-Type' header, it not works for Retrofit 2.0.0 // @Headers({"Content-Type: image/png"}) @GET Call<ResponseBody> fetchCaptcha(@Url String url); } Call<ResponseBody> call = api.fetchCaptcha(url); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if (response.isSuccessful()) { if (response.body() != null) { // display the image data in a ImageView or save it Bitmap bm = BitmapFactory.decodeStream(response.body().byteStream()); ivCaptcha.setImageBitmap(bm); } else { // TODO } } else { // TODO } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { // TODO } }); 

另一种方法是closures完整的日志logging,所以retrofit.RestAdapter.logAndReplaceResponse将不会尝试使用响应主体