Retrofit
Square社開発のタイプセーフなHTTPクライアント。REST APIを宣言的インターフェースに変換し、アノテーションベースでAPIコールを定義。GsonやMoshi等のシリアライゼーションライブラリと統合し、RxJavaやKotlin Coroutinesをサポート。
概要
Retrofitは、Square社が開発したJavaとAndroid向けのタイプセーフなHTTPクライアントライブラリです。RESTful APIとの通信を簡素化し、インターフェースとアノテーションを使用してAPIエンドポイントを定義できます。
主な特徴
- タイプセーフなAPI定義: インターフェースとアノテーションベースの設計
- 自動シリアライゼーション: GsonやMoshiなどの各種コンバーターをサポート
- 非同期処理サポート: RxJava、Kotlin Coroutinesとの統合
- OkHttpベース: 強力なHTTPクライアントエンジン
- 拡張性: カスタムコンバーターやアダプターの実装が可能
- インターセプター: リクエスト/レスポンスの加工や認証処理
インストール
Gradle
dependencies {
// Retrofit 3.0 (最新版)
implementation 'com.squareup.retrofit2:retrofit:3.0.0'
// Gsonコンバーター
implementation 'com.squareup.retrofit2:converter-gson:3.0.0'
// RxJavaアダプター(オプション)
implementation 'com.squareup.retrofit2:adapter-rxjava3:3.0.0'
}
Maven
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>3.0.0</version>
</dependency>
基本的な使い方
APIインターフェースの定義
public interface GitHubService {
@GET("users/{user}/repos")
Call<List<Repo>> listRepos(@Path("user") String user);
@GET("user")
Call<User> getUser(@Header("Authorization") String token);
}
Retrofitインスタンスの作成
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
実装例
1. GETリクエスト
public interface UserService {
// シンプルなGETリクエスト
@GET("users/{id}")
Call<User> getUser(@Path("id") long userId);
// クエリパラメータ付き
@GET("users")
Call<List<User>> getUsers(
@Query("page") int page,
@Query("per_page") int perPage
);
// 複数のクエリパラメータ
@GET("search/repositories")
Call<SearchResult> searchRepos(@QueryMap Map<String, String> options);
}
// 使用例
Call<User> call = userService.getUser(123);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User user = response.body();
// ユーザー情報を処理
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// エラー処理
}
});
2. POSTリクエスト
public interface ApiService {
// JSONボディ
@POST("users")
Call<User> createUser(@Body User user);
// フォームエンコード
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(
@Field("first_name") String firstName,
@Field("last_name") String lastName
);
// マルチパート
@Multipart
@POST("upload")
Call<ResponseBody> uploadImage(
@Part MultipartBody.Part image,
@Part("description") RequestBody description
);
}
// 使用例:JSON送信
User newUser = new User("John", "Doe");
Call<User> call = apiService.createUser(newUser);
Response<User> response = call.execute(); // 同期実行
3. 認証処理
// インターセプターを使用した認証
public class AuthInterceptor implements Interceptor {
private String authToken;
public AuthInterceptor(String token) {
this.authToken = token;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.header("Authorization", "Bearer " + authToken);
Request request = builder.build();
return chain.proceed(request);
}
}
// OkHttpクライアントに追加
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new AuthInterceptor(authToken))
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
4. エラーハンドリング
public class ApiClient {
public void handleApiCall() {
Call<User> call = service.getUser(userId);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
User user = response.body();
// 成功処理
} else {
// HTTPエラー処理
try {
ErrorResponse error = gson.fromJson(
response.errorBody().string(),
ErrorResponse.class
);
handleError(error);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
if (t instanceof SocketTimeoutException) {
// タイムアウト処理
} else if (t instanceof IOException) {
// ネットワークエラー処理
} else {
// その他のエラー処理
}
}
});
}
}
5. ファイルアップロード
public interface FileUploadService {
@Multipart
@POST("upload")
Call<UploadResponse> uploadFile(
@Part MultipartBody.Part file,
@Part("description") RequestBody description
);
@Multipart
@POST("upload/multiple")
Call<UploadResponse> uploadMultipleFiles(
@Part List<MultipartBody.Part> files
);
}
// 使用例
File file = new File(filePath);
RequestBody requestFile = RequestBody.create(
MediaType.parse("image/*"),
file
);
MultipartBody.Part body = MultipartBody.Part.createFormData(
"file",
file.getName(),
requestFile
);
RequestBody description = RequestBody.create(
MediaType.parse("text/plain"),
"画像の説明"
);
Call<UploadResponse> call = service.uploadFile(body, description);
6. Kotlin Coroutinesの使用(Retrofit 3.0)
interface ApiService {
@GET("posts")
suspend fun getPosts(): List<Post>
@POST("posts")
suspend fun createPost(@Body post: Post): Post
}
// ViewModelでの使用
class PostViewModel : ViewModel() {
private val apiService = RetrofitClient.apiService
fun loadPosts() {
viewModelScope.launch {
try {
val posts = apiService.getPosts()
// UIを更新
} catch (e: HttpException) {
// HTTPエラー処理
val code = e.code()
val message = e.message()
} catch (e: Exception) {
// その他のエラー処理
}
}
}
}
7. 進捗状況の監視
public interface DownloadService {
@Streaming
@GET
Call<ResponseBody> downloadFile(@Url String fileUrl);
}
// プログレス付きダウンロード
public void downloadFileWithProgress(String fileUrl) {
Call<ResponseBody> call = service.downloadFile(fileUrl);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {
new Thread(() -> {
writeResponseBodyToDisk(response.body());
}).start();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
// エラー処理
}
});
}
private boolean writeResponseBodyToDisk(ResponseBody body) {
try {
File file = new File(getExternalFilesDir(null) + File.separator + "download.file");
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(file);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) break;
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
// 進捗を計算してUIを更新
int progress = (int) ((fileSizeDownloaded * 100) / fileSize);
publishProgress(progress);
}
outputStream.flush();
return true;
} catch (IOException e) {
return false;
} finally {
if (inputStream != null) inputStream.close();
if (outputStream != null) outputStream.close();
}
} catch (IOException e) {
return false;
}
}
他のライブラリとの比較
Retrofit vs OkHttp
- Retrofit: 高レベルなRESTクライアント、アノテーションベース
- OkHttp: 低レベルなHTTPクライアント、より細かい制御が可能
Retrofit vs Volley
- Retrofit: タイプセーフ、RxJava/Coroutinesサポート、大規模アプリ向け
- Volley: Googleが開発、画像処理に強い、小規模アプリ向け
Retrofit vs Fuel
- Retrofit: Java/Android標準、豊富なエコシステム
- Fuel: Kotlin専用、よりシンプルなAPI
ベストプラクティス
-
シングルトンパターンの使用
public class RetrofitClient { private static Retrofit retrofit = null; public static Retrofit getClient(String baseUrl) { if (retrofit == null) { retrofit = new Retrofit.Builder() .baseUrl(baseUrl) .addConverterFactory(GsonConverterFactory.create()) .build(); } return retrofit; } } -
タイムアウトの設定
OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .build(); -
ログ出力の追加
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(); logging.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(logging) .build(); -
エラーレスポンスの統一処理
public class ApiError { private int statusCode; private String message; public static ApiError parseError(Response<?> response) { Converter<ResponseBody, ApiError> converter = retrofit.responseBodyConverter(ApiError.class, new Annotation[0]); ApiError error; try { error = converter.convert(response.errorBody()); } catch (IOException e) { return new ApiError(); } return error; } }
まとめ
Retrofitは、JavaとAndroidにおけるHTTP通信の標準的なライブラリとして広く採用されています。タイプセーフなAPI定義、豊富な機能、そして優れた拡張性により、小規模から大規模まで様々なアプリケーションで活用できます。特に、RESTful APIとの通信が多いアプリケーションでは、その真価を発揮します。