Upload from android gallery to Server

FIrst, I have to apologize for posting this here instead of the Android Development board - I have bought subscription but for whatever reason it’s not updated here on the board - can you please check what’s going on? (please move this in the Android Development board)

I am trying to upload files from android device to server in order to that I fetched URI like

suspend fun listVideos(): List<VideoModel>? =
    withContext(Dispatchers.IO) {
      val resolver = context.contentResolver

      resolver.query(collection, PROJECTION, null, null, SORT_ORDER)
        ?.use { cursor ->
          cursor.mapToList {
            VideoModel(
              it.getLong(0),
              it.getString(1),
              it.getString(2),
              it.getString(3)
            )
          }
        }
    }

after that I created InputStreamRequestBody:

fun prepareFilePart(partName: String, uri: Uri, context: Context, name: String): MultipartBody.Part {
        val inputStream = context.contentResolver.openInputStream(uri)
        val requestBody: RequestBody =
                RequestBodyUtil.create(MediaType.parse(context.contentResolver.getType(uri)), inputStream)


        return MultipartBody.Part.createFormData(partName, name, requestBody)
    }

Here is retrofit stuff:

public interface PlatformGroupPostService {

@Multipart
@POST("brainy/api/v0/post")
Observable<NewGroupAPIResponse> createPost(@Part("postData") RequestBody postData,
                                           @Part MultipartBody.Part attachments);

}

But on server side I am always getting null file reference

Kindly suggest what could be the best way to achieve this feature

You have to request access to post to this board on the Warescription site, and I have to manually grant that access. That has now all been taken care of.

I do not know what RequestBodyUtil is. The InputStreamRequestBody that I point people to is this one (see the second listing in that GitHub issue comment). It works off of a Uri and a ContentResolver, as OkHttp may need to open the stream multiple times (see other discussion in that GitHub issue).

Personally, I have never needed to upload anything using @Part so I have not needed to use that InputStreamRequestBody. However, this topic is coming up enough that I may need to find some Web service API that needs this stuff, just so I can write a complete example of the process…

Regardless, I would try the InputStreamRequestBody that I linked to and see if that changes anything for you.

I followed you and used this class:

public class InputStreamRequestBody extends RequestBody {

private final MediaType contentType;
private final ContentResolver contentResolver;
private final Uri uri;

public InputStreamRequestBody(MediaType contentType, ContentResolver contentResolver, Uri uri) {
    if (uri == null) throw new NullPointerException("uri == null");
    this.contentType = contentType;
    this.contentResolver = contentResolver;
    this.uri = uri;
}

@Nullable
@Override
public MediaType contentType() {
    return contentType;
}

@Override
public long contentLength() {
    return -1;
}

@Override
public void writeTo(@NonNull BufferedSink sink) throws IOException {
    try (Source source = Okio.source(contentResolver.openInputStream(uri))) {
        sink.writeAll(source);
    }
}

}

But somehow this feature screwed me alot dont have idea, what to do now, could you please enlighten me

also if you want I can share mine Web Service API

I do not know what “screwed me alot” means.

Sorry it was my bad, It meant like I am stuck since last 6 days without any clue, just exploring different blogs and stackoverflow and try to implement different-2 solution

You might consider running an experiment:

  • Create a file in getFilesDir()
  • Try uploading that file using more conventional RequestBody options

If that fails, then my guess is that there is some disconnect between your Retrofit definition and what the server is expecting.

If that succeeds, then you know the problem is tied to trying to upload from the Uri. Worst-case, you can copy the content identified by the Uri to a file, then upload the file. I have not had to do this sort of multipart upload personally.

More generally: your original question was very well-written! But, follow-up questions need that same level of care. Saying “screwed me alot” does not help anyone help you. Providing technical details of what you tried and what you are seeing might help others help you.

You are right will take care, finally I have done that things, Now I am able to upload multiple video from android gallery to my server . Issue have been resolved.

As you told some disconnection between retrofit and server : Its 100% right in my case. I had put wrong multi part name here :slightly_smiling_face:

MultipartBody.Part.createFormData(partName, name, requestBody)

along With:

   val requestBody: RequestBody = RequestBody.create(
                MediaType.parse(context.contentResolver.getType(uri)),
                getBytes(context.contentResolver.openInputStream(uri))
              )

@Throws(IOException::class)
        fun getBytes(inputStream: InputStream?): ByteArray? {
            if(inputStream == null)
                return null

            val byteBuff = ByteArrayOutputStream()
            val buffSize = inputStream.available()
            val buff = ByteArray(buffSize)
            var len = 0
            while (inputStream.read(buff).also({ len = it }) != -1) {
                byteBuff.write(buff, 0, len)
            }
            return byteBuff.toByteArray()
        }

Thanks a lot again for your help and quick response.Kindly share your suggestion on above step. Also if anyone want to whole solution please let me know I will try to share