Android 使用改造下载图像文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24158321/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use retrofit to download image file
提问by Denny Huang
I use Retrofit 1.6.0 on my Android project,
我在我的 Android 项目上使用 Retrofit 1.6.0,
the request url:
请求网址:
https://example.com/image/thumbs/filename/sample.png
https://example.com/image/thumbs/filename/sample.png
My interface like this:
我的界面是这样的:
public interface ImageService {
@GET("/image/thumbs/filename/{filename}")
@Streaming
void getThumbs(
@Path("filename") String filename,
Callback<Response> callback
);
}
HTTP request was success, but there some error occur
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.access0(RestAdapter.java:109)
D/Retrofit(27613): at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:333)
D/Retrofit(27613): at retrofit.RestAdapter$RestHandler.access0(RestAdapter.java:220)
D/Retrofit(27613): at retrofit.RestAdapter$RestHandler.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.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
How do I solve this problem?
我该如何解决这个问题?
回答by Jesse Wilson
The issue is the content-type header on the response includes a bogus charset:
问题是响应中的内容类型标头包含一个虚假字符集:
Content-Type: image/png; charset=binary
Retrofit sees this and infers that the response is text that it can log. You should report the problem to the server's administrator.
Retrofit 看到这一点并推断响应是它可以记录的文本。您应该将问题报告给服务器管理员。
If you report the issue to Retrofit's issue tracker on GitHub, we can probably recover from this problem rather than crashing.
如果您将问题报告给 GitHub 上的 Retrofit 问题跟踪器,我们可能可以从此问题中恢复而不是崩溃。
回答by Haojun Fan
I am playing with rxjava and retrofit these days, I have a quick demo here. Talk is cheap, show you my code directly, hope it helps.
这些天我正在玩 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);
}
}
}
And I wrote my own BitmapConverterFactory to convert byte stream to bitmap:
我编写了自己的 BitmapConverterFactory 来将字节流转换为位图:
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 dependencies here:
Gradle 依赖项在这里:
final RETROFIT_VERSION = '2.0.0-beta3'
compile "com.squareup.retrofit2:retrofit:$RETROFIT_VERSION"
compile "com.squareup.retrofit2:adapter-rxjava:$RETROFIT_VERSION"
Cheers, vanvency
干杯,万文达
回答by Spark.Bao
Of course we usually use Picasso to load image, but sometimes we really need use Retrofit to load a special image (like fetch a captcha image), you need add some header for request, get some value from header of response (of course you can also use Picasso + OkHttp, but in a project you have already use Retrofit to handle most of net requests), so here introduce how to implement by Retrofit 2.0.0 (I have already implemented in my project).
当然我们通常使用 Picasso 来加载图片,但有时我们真的需要使用 Retrofit 来加载一个特殊的图片(比如获取验证码图片),你需要为请求添加一些头部,从响应头部中获取一些值(当然你可以也使用Picasso + OkHttp,但是在一个项目中你已经使用了Retrofit来处理大部分的网络请求),所以这里介绍一下如何通过Retrofit 2.0.0来实现(我已经在我的项目中实现了)。
The key point is that you need use okhttp3.ResponseBody
to receive response, else Retrofit will parse the response data as JSON, not binary data.
关键是你需要okhttp3.ResponseBody
用来接收响应,否则 Retrofit 会将响应数据解析为 JSON,而不是二进制数据。
codes:
代码:
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
}
});
回答by avgx
Another way is to turn off full logging, so the retrofit.RestAdapter.logAndReplaceResponse will not try to consume the response body
另一种方法是关闭完整日志记录,因此改造.RestAdapter.logAndReplaceResponse 不会尝试使用响应正文