LoginSignup
13
8

More than 3 years have passed since last update.

Retrofit2でMultipartPOST

Last updated at Posted at 2017-06-04

すぐ忘れるのでメモ。
間違いなどあったら是非指摘していただきたいです。

やりたいこと

タイトルにある通り。
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へ投げる例。

api.java
@POST("/post")
Single<Response<StatusResponse>> createPost(@Body RequestBody images);

@Multipartが必要なのかと思っていたが、必要無かった。

2.RequestBodyの生成

Okhttp3.RequestBodyに存在するBuilderを使って生成する。

PostService.java
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 さん、ありがとうございました:bow:

--追記ここまで--

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などから、実際に呼び出す。

HogeRepository.java
//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に反映させたりする。

13
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
8