retrofit/CHANGELOG.md at master · square/retrofit
retrofit との後方互換性はありません。そのため maven の group id が com.squareup.retrofit2 になっています。
- compile 'com.squareup.retrofit2:retrofit:2.0.0'
Converter
GSON などの Converter は別のモジュールに分割されました。
retrofit
- new RestAdapter.Builder()
- .setConverter(new GsonConverter(gson))
- ...
- compile 'com.squareup.retrofit2:converter-gson:2.0.0'
- new Retrofit.Builder()
- .addConverterFactory(GsonConverterFactory.create(gson))
- ...
RxJava
retrofit で RxJava を使うためのクラスは別のモジュールに分割されました。
retrofit2
- compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0'
- new Retrofit.Builder()
- .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
- ...
AndroidLog
retrofit.android.AndroidLog はなくなりました。 https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor
を使って okhttp3 の interceptor で行います。
retrofit
- AndroidLog logger = new AndroidLog(MyService.class.getSimpleName());
- new RestAdapter.Builder()
- .setLogLevel(RestAdapter.LogLevel.FULL)
- .setLog(logger)
- ...
- compile 'com.squareup.okhttp3:logging-interceptor:3.0.0'
- HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
- logging.setLevel(HttpLoggingInterceptor.Level.BODY);
- new OkHttpClient.Builder();
- .addInterceptor(logging)
- ...
ErrorHandler, RetrofitError
retrofit.ErrorHandler, retrofit.RetrofitError はなくなりました。
okhttp3 の interceptor で行うとか https://github.com/square/retrofit/issues/1102
CallAdapterFactory を作るとか https://github.com/square/retrofit/pull/1277/files
いくつか方法があります。
adapter-rxjava を使っているなら HttpException が onError() で返されるので、ここから status code, message, response が取れます。
retrofit
- new RestAdapter.Builder()
- .setErrorHandler(new MyErrorHandler())
- ...
- public class MyErrorHandler implements ErrorHandler {
- @Override
- public Throwable handleError(RetrofitError cause) {
- if (cause.getKind() == RetrofitError.Kind.NETWORK) {
- // network error
- ...
- } else if (cause.getResponse() != null) {
- final int statusCode = cause.getResponse().getStatus();
- try {
- MyErrorResponse errorResponse =
- (MyErrorResponse) cause.getBodyAs(MyErrorResponse.class);
- } catch (Exception e) {
- ...
- }
- } else {
- ...
- }
- }
- }
- @Override
- public void onError(Throwable e) {
- if (e instanceof IOException) {
- // network error
- ...
- } else if (e instanceof HttpException) {
- HttpException he = (HttpException) e;
- final int statusCode = he.code();
- final ResponseBody errorBody = e.response().errorBody();
- if (errorBody != null) {
- try {
- MyErrorResponse errorResponse =
- (MyErrorResponse) GsonConverterFactory
- .create()
- .responseBodyConverter(MyErrorResponse.class,
- new Annotation[0], null)
- .convert(errorBody);
- // retrofit インスタンスが利用できる場合
- // MyErrorResponse errorResponse = retrofit
- // .responseConverter(MyErrorResponse.class, new Annotation[0])
- // .convert(errorBody);
- } catch (Exception re) {
- ...
- }
- }
- } else {
- ...
- }
- }
RequestInterceptor
retrofit.RequestInterceptor はなくなりました。
okhttp3 の interceptor を使います。https://github.com/square/retrofit/issues/1082
retrofit
- public class MyRequestInterceptor implements RequestInterceptor {
- @Override
- public void intercept(RequestFacade request) {
- request.addHeader(HEADER_KEY, headerValue);
- }
- }
- new RestAdapter.Builder()
- .setRequestInterceptor(new MyRequestInterceptor())
- ...
- public class MyRequestInterceptor implements Interceptor {
- @Override
- public Response intercept(Chain chain) throws IOException {
- final Request.Builder builder = chain.request().newBuilder();
- builder.addHeader(HEADER_KEY, headerValue);
- return chain.proceed(builder.build());
- }
- }
- new OkHttpClient.Builder()
- .addInterceptor(new MyRequestInterceptor())
- ...
Response
import 先を変更する必要があります。
retrofit
- import retrofit.client.Response
- import retrofit2.Response
Observable<Response>
ResponseBody を指定する必要があります。
retrofit
- @DELETE("/delete")
- Observable<Response> delete();
- @DELETE("/delete")
- Observable<Response<ResponseBody>> delete();
@Body, @GET, @Post など
import 先を変更する必要があります。
retrofit
- import retrofit.http.Body
- import retrofit2.http.Body
retrofit
- @Query(value = "categories", encodeValue = false) @Nullable String categories
- @Query(value = "categories", encoded = false) @Nullable String categories
TypedFile
TypedFile はなくなりました。
MultipartBody.Part を使います。
retrofit
- @Multipart
- @POST("/upload")
- Observable<Response> uploadImage(
- @Part("image") TypedFile image
- );
- final TypedFile image = new TypedFile("image/jpeg", file);
- @Multipart
- @PATCH("/upload")
- Observable<Response> uploadImage(
- @Part() MultipartBody.Part image
- );
- final MultipartBody.Part image = MultipartBody.Part.createFormData("image",
- file.getName(),
- RequestBody.create(MediaType.parse("image/jpeg"), file));
Client
retrofit.client.Client はなくなりました。
retrofit側でモック化したい場合は retrofit-mock があります。
- compile 'com.squareup.retrofit2:retrofit-mock:2.0.0'
https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/SimpleMockService.java が参考になります。
okhttp側でモック化したい場合は mockwebserverがあります。
- compile 'com.squareup.okhttp3:mockwebserver:3.0.0'
okhttp
okhttp3 を使います。
retrofit
- import com.squareup.okhttp.Interceptor;
- import com.squareup.okhttp.Request;
- import com.squareup.okhttp.Response;
- import okhttp3.Interceptor;
- import okhttp3.Request;
- import okhttp3.Response;
stetho-okhttp
stetho-okhttp3 を使います。https://github.com/facebook/stetho/issues/327
retrofit2
- compile 'com.facebook.stetho:stetho-okhttp3:1.3.1'
java.io.InterruptedIOException: thread interrupted
Retrofit2 (というか okhttp3)にして
- thread interrupted
- java.io.InterruptedIOException: thread interrupted
- at okio.Timeout.throwIfReached(Timeout.java:145)
- at okio.Okio$1.write(Okio.java:77)
- ...
例えば以下のような、subscribeOn(Schedulers.newThread()) を指定した複数の Observable を merge して takeLast すると InterruptedIOExceptionになります。 zip や combineLatest だと問題ないです。
NG
- final List<Observable<ImageResponse>> observables = new ArrayList<>();
- for (...) {
- final MultipartBody.Part image = ...;
- final Observable<ImageResponse> o = service.uploadImage(image)
- .subscribeOn(Schedulers.newThread());
- observables.add(o);
- }
- Observable
- .merge(observables)
- .takeLast(1)
- .subscribeOn(Schedulers.newThread());
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new Subscriber<ImageResponse>() {
- ...
- });
- final List<Observable<ImageResponse>> observables = new ArrayList<>();
- for (...) {
- final MultipartBody.Part image = ...;
- final Observable<ImageResponse> o = service.uploadImage(image)
- .subscribeOn(Schedulers.newThread());
- observables.add(o);
- }
- Observable
- .combineLatest(observables, new FuncN<ImageResponse>() {
- @Override
- public ImageResponse call(Object... args) {
- return ...;
- }
- })
- .subscribeOn(Schedulers.newThread());
- .observeOn(AndroidSchedulers.mainThread())
- .subscribe(new Subscriber<ImageResponse>() {
- ...
- });