まえがき
Android開発で少し手こずったので備忘録として,載せておきます.
幾分冗長だなとか多々あると思いますが,長い目でよろしくお願いします.
やりたいこと
Android開発で画像とテキストをmultipart
で自社サーバへ同時送信
使用ライブラリ
Retrofit2
仕様
概要
今回はチャットのようなアプリをイメージしてください.
送信は以下の4通りに分かれます.
画像 | テキスト | 備考 |
---|---|---|
◯ | ◯ | 画像とテキスト同時送信 |
◯ | × | 画像のみ送信 |
× | ◯ | テキストのみ送信 |
× | × | 何も入力されていない |
今回の実装プログラムでは,上3つに対応しております.
一番下は必ずエラー処理として,PopUpみたいなのを出すといいと思われます.
今回は実装してないです.
WebAPIの仕様
画像とテキストを投稿するにあたってサーバへPOSTリクエストを行います.
ここで,POSTリクエストの際に以下のようなbodyが要求されています.
パラメタ | 型 | 備考 |
---|---|---|
user_id | int | 誰が送ったのかが必要なので必須 |
message | string | 投稿本文 |
img_file | string | 画像 |
送信実装
ライブラリのインストール
本セクションでは使用したライブラリを記述します.
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型
です!
これは注意です.
まず実装コードです.
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)
}
...
次にレスポンスモデルです.
import java.io.Serializable
data class PostResponse(
var message: String
) : Serializable
次に,Retrofit
を用いる時のインタフェースです.
...
@JvmSuppressWildcards
@Multipart
@POST("/ディレクトリhoge/ディレクトリfuga")
fun postEntry(
@PartMap params: Map<String, RequestBody>): Observable<PostResponse>
...
終わりに
ちょっと改造してテストはしてないですが,こちらで多分通ると思います.
質問や改善要求などどしどしためらいもなく,うぇるかむです.
読んでいただきありがとうございました.
swiftの場合-> https://qiita.com/hisakioomae/items/0190165674fd241454d4