Simone Cascino
Simone Cascino

Reputation: 105

Upload files using retrofit 2 without the file instance (filedescriptor or inputstream), or obtain the file instance from the content uri

I have already uploaded file with retrofit using formdata and @Part, but I always had a file instance, and I could easily convert it to request body with the extension function "asRequestBody", included in the RequestBody class.

But now I need to use a different approach. In my app the user doesn't have limitation of the type of file (can be an image, a pdf, or something else), so, according to the documentation I'm using the following approach:

val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "*/*"
}
requireActivity().startActivityForResult(intent, REQUEST_CODE_PICK_ID)

It works, and after the file selection, I obtain the content uri of the file in the onActivityResult. I'm able to query the content provider to obtain a small amount of information (filename for example), and I can convert the content uri in a filedescriptor or an inputstream using the content resolver. But I don't have the file instance, that I need to use to convert the file into a RequestBody.

I can obtain a bytearray from the inputstream and I could use it (there is another extension function in the request body), but is it the right approach? If the file is big, could it be bad in terms of performance?

I could create a copy of the file using the inputstream, but I don't like this approach, the official documentation says to use open_document instead of get_content as action of the intent to avoid copy creation of the file.

So, how can I use the filedescriptor or the inputstream with retrofit? There is a way to obtain a File instance from the content uri?

Upvotes: 1

Views: 1014

Answers (1)

Arunachalam k
Arunachalam k

Reputation: 744

You can get Input stream Object from content provider by passing your Uri once u gets it convert input stream to byte array by following below code

You can use Apache Commons IO to handle this and similar tasks.

The IOUtils type has a static method to read an InputStream and return a byte[].

InputStream is;
byte[] bytes = IOUtils.toByteArray(is);

In Retrofit 2.7.1 There is an Extension class named Request body There is an extension method to convert byte array into request body

   @JvmOverloads
@JvmStatic
@JvmName("create")
fun ByteArray.toRequestBody(
  contentType: MediaType? = null,
  offset: Int = 0,
  byteCount: Int = size
): RequestBody {
  checkOffsetAndCount(size.toLong(), offset.toLong(), byteCount.toLong())
  return object : RequestBody() {
    override fun contentType() = contentType

    override fun contentLength() = byteCount.toLong()

    override fun writeTo(sink: BufferedSink) {
      sink.write(this@toRequestBody, offset, byteCount)
    }
  }
}

Upvotes: 0

Related Questions