LoginSignup
8
14

More than 3 years have passed since last update.

Androidでmultipartで画像とテキストを同時送信

Last updated at Posted at 2018-10-09

まえがき

Android開発で少し手こずったので備忘録として,載せておきます.
幾分冗長だなとか多々あると思いますが,長い目でよろしくお願いします.:star2:

やりたいこと

Android開発で画像とテキストをmultipartで自社サーバへ同時送信

使用ライブラリ

Retrofit2

仕様

概要

今回はチャットのようなアプリをイメージしてください.
送信は以下の4通りに分かれます.

画像 テキスト 備考
画像とテキスト同時送信
× 画像のみ送信
× テキストのみ送信
× × 何も入力されていない

今回の実装プログラムでは,上3つに対応しております.
一番下は必ずエラー処理として,PopUpみたいなのを出すといいと思われます.
今回は実装してないです.:frowning2:

WebAPIの仕様

画像とテキストを投稿するにあたってサーバへPOSTリクエストを行います.
ここで,POSTリクエストの際に以下のようなbodyが要求されています.

パラメタ 備考
user_id int 誰が送ったのかが必要なので必須
message string 投稿本文
img_file string 画像

送信実装

ライブラリのインストール

本セクションでは使用したライブラリを記述します.

build.gradle
dependencies {
...
    //==================== Network ====================
    implementation "com.squareup.okhttp3:logging-interceptor:3.9.1"
    implementation "com.squareup.retrofit2:retrofit:2.3.0"
    implementation "com.squareup.retrofit2:converter-moshi:2.3.0"
    implementation "com.squareup.retrofit2:adapter-rxjava:2.3.0"

...
}

送信

本セクションでは実際にコードを使ってmultipart送信を行います.
postEntry関数を呼び出すと投稿が実行されます.
画像は写真で撮影およびギャラリーからの参照で取得できると思いますが,それはここではあえて言いません.
画像はFile型です!
これは注意です.

まず実装コードです.

MainActivity.kt

import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory
import retrofit2.converter.moshi.MoshiConverterFactory

...

/**
 * 投稿を送信する関数
 */
private fun postEntry(userId: Int, body: String, image: File) {
    // =====送信するデータを整形する=====
    val map: MutableMap<String, RequestBody> = HashMap() // このオブジェクトを送信する

    val userId = RequestBody.create(MediaType.parse("text/plain"), userId.toString())
    val body = RequestBody.create(MediaType.parse("text/plain"), body)
    val requestBody = RequestBody.create(MediaType.parse("image/jpg"), image) // 拡張子は任意で変えてください
    map.put("user_id", userId)
    map.put("body", body)
    map.put("img_file\"; filename=\"image.png\"", requestBody)

    createApiClient().postEntry(params = map)
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object: Subscriber<PostResponse>() {
                override fun onNext(r: PostResponse?) {  // 成功
                    Log.d("MainActivity", r.toString())
                }
                override fun onError(e: Throwable?) {
                    Log.d("MainActivity", e.toString())  // 失敗
                }
                override fun onCompleted() {
                }
            })
}

...

/**
 * APIクライアントのインスタンスを生成して返却する関数
 */

fun createApiClient(): Api {
    val moshi = Moshi.Builder()
            .build()
    val okClient = OkHttpClient()

    val builder = Retrofit.Builder()
            .client(okClient)
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .baseUrl("https://自社サーバのどめいん/")
            .build()
    return builder.create(ApiInterface::class.java)
}

...

次にレスポンスモデルです.

PostResponse.kt
import java.io.Serializable

data class PostResponse(
        var message: String
) : Serializable

次に,Retrofitを用いる時のインタフェースです.

ApiInterface.kt
...
@JvmSuppressWildcards
@Multipart
@POST("/ディレクトリhoge/ディレクトリfuga")
fun postEntry(
        @PartMap params: Map<String, RequestBody>): Observable<PostResponse>
...

終わりに

ちょっと改造してテストはしてないですが,こちらで多分通ると思います.
質問や改善要求などどしどしためらいもなく,うぇるかむです.
読んでいただきありがとうございました.

swiftの場合-> https://qiita.com/hisakioomae/items/0190165674fd241454d4

8
14
0

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
8
14