すぐ忘れるのでメモ。
間違いなどあったら是非指摘していただきたいです。
##やりたいこと
タイトルにある通り。
APIに画像を投げたいとか、そういう場合を想定してます。
##環境
- AndroidStudio 2.3.2
- buildToolVersion 25.0.2
- Retrofit2 2.2.0
- Okhttp 3.8.0
- Retrolambda 3.3.0
- RxJava2 2.0.8
- RxAndroid 2.0.1
##方法
###1.interfaceの定義
@Body
アノテーションを付与したRequestBoby
を定義するインタフェースの引数に含める。
以下は、/post
へ投げる例。
@POST("/post")
Single<Response<StatusResponse>> createPost(@Body RequestBody images);
@Multipart
が必要なのかと思っていたが、必要無かった。
###2.RequestBody
の生成
Okhttp3.RequestBody
に存在するBuilder
を使って生成する。
MultipartBody.Builder builder = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("caption", intent.getStringExtra("caption"));
for (File file : files) {
builder.addFormDataPart("media", file.getName(),
// RequestBody.createが廃止されたので、file.toRequestBodyに修正
file.toRequestBody("image/jpg".toMediaTypeOrNull(), 0, file.size)
}
RequestBody body = builder.build();
2020/09/30追記
RequestBody.createが廃止されたので、file.toRequestBodyに修正しました。
修正提案いただきました @mizukicker さん、ありがとうございました
--追記ここまで--
####setType
Content-Typeを指定する。Content-Typeは以下のようなもの
- multipart/form-data
- application/octet-stream
- text/plain
- image/jpeg
などなど
RequestBody
には、次のTypeが定義されている。
値 | Content-Type |
---|---|
FORM | multipart/form-data |
MIXED | multipart/mixed |
ALTERNATIVE | multipart/alternative |
DIGEST | multipart/digest |
PARALLEL | multipart/parallel |
内部的には各値に対応する文字列をMediaType.parse()
に渡している。
今回は上記のうちFORM
を使っています。
####addFormDataPart
nameとvalueを引数に取るものと、nameとfileNameとbodyを引数に取るものがあります。
単なる文字列ならば(name, value)
で。
画像とかのファイルならば(name, fileName, value)
を使う。
後者では、第3引数にRequestBodyが必要。
RequestBody.create()
などで作ってやればOK。
###3.呼び出して実行
ViewModelやRepositoryなどから、実際に呼び出す。
//Maybe<T>を返す
return ApiClient.postApi.createPost(body)
.compose(DebugTransformer.withSingle("createNewPost"))
.doOnError(throwable -> {
Log.d("debug", "error: createNewPost");
throwable.printStackTrace();
})
.filter(response -> response.body() != null)
.map(response -> response.body().status);
上記はRepositoryでの実装例。
実際には、ViewModelなどでsubscribeしておき、APIコールの結果を使ってViewに反映させたりする。