使用 Retrofit2 + RxJava 請求圖片 URL 時拋出異常:
com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
原因很明顯:服務器返回的是二進制圖片數據(JPG),而非 JSON。但 Retrofit 默認配置了 GsonConverterFactory,會嘗試將響應體解析為 JSON,導致解析失敗。
Observable<ResponseBody> getImg(@Url String url) 返回類型應為 ResponseBody 或 byte[],而非泛型未指定的 Observable。GsonConverterFactory 會攔截所有響應並嘗試 JSON 解析,圖片二進制數據無法解析。okhttp3.ResponseBody 與 okhttp.ResponseBody(2.x 版本)轉換失敗,說明依賴版本衝突。Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://pic41.nipic.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 注意 RxJava 2.x 用法
// .addConverterFactory(GsonConverterFactory.create()) // 刪除這行!
.build();
ImgService service = retrofit.create(ImgService.class);
service.getImg("https://pic41.nipic.com/20140509/4746986_145156378323_2.jpg")
.subscribeOn(Schedulers.io())
.map(responseBody -> {
// 直接處理字節流
return BitmapFactory.decodeStream(responseBody.byteStream());
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmap -> imageView.setImageBitmap(bitmap),
throwable -> throwable.printStackTrace());
.addConverterFactory(new Converter.Factory() {
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new Converter<ResponseBody, ResponseBody>() {
@Override
public ResponseBody convert(ResponseBody value) throws IOException {
return value; // 直接透傳
}
};
}
})
public interface ImgService {
@GET
Observable<ResponseBody> getImg(@Url String url); // 必須指定泛型
}
確保 build.gradle 中 OkHttp、Retrofit、RxJava 版本一致:
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
請求圖片/文件時:不要添加 GsonConverterFactory,直接使用 ResponseBody 或 byte[] 作為返回類型,Retrofit 內置轉換器會自動處理二進制數據。