AndroidでUriからOkHttpのRequestBodyを作る

Android開発で、Uriが指している画像をRequestBodyに入れてRetrofitでサーバーにPOSTしようとしましたが、解決する途中で様々な問題が出てつまづいたので記事にしました。

 

一般的(??)なRequestBodyの作り方

RequestBody (OkHttp 3.9.0 API)

RequestBodyにはファクトリメソッドが用意されているので、それを使ってインスタンスを作ります。Fileを渡す方法や、byte配列を直接渡す方法があります。

今回はAndroidUriが指しているファイルをRequestBodyに入れたいので、うまくいきません。

解決法1 UriからFileに変換して、Fileを渡す

もっとも簡単そうな解決方法ですが、うまくいかない場合があります。

qiita.com

この記事やこの記事中に貼ってあるStackOverflowにUriからFileに変換する方法が掲載されています。同記事にも書いてありますが、この方法ではカメラを開いて撮影した画像などを指すUriはFileに変換できません。UriによってFileに変換する方法が違うので、UriをFileに変換するのはとてもめんどくさそうです。

 

解決法2 byte配列を渡す

ContentResolverを使ってFileからInputStreamを取得できるので、一旦ファイルの内容をbyte配列に入れてRequestBodyを作る方法です。

Android 画像ファイルを扱う際のFileとUriまとめ - Qiita

やってみましたが、5MBくらいの画像を扱うとOutOfMemoryErrorが発生したり、GCが頻発して重くなりアップロードに50秒くらいかかったりしてうまくいきませんでした。

解決法3 RequestBodyを実装する

既存のファクトリメソッドを使う方法ではうまくいかなさそうなので、自分で実装します。

RequestBodyのcreateメソッドの中には、RequestBodyの抽象メソッドの実装が書かれているので、これを参考にします。

github.com

 

Kotlinで実装しました。

gist.github.com

 

本当はRequestBodyのstaticな拡張関数(KotlinのCompanion objectの拡張関数みたいな??)として定義しようとしました。しかし、RequestBodyのようにCompanion objectを持っていないJavaのクラスの場合、それはできないようです。

もっといい方法や間違いなどあれば、マサカリを投げてください。