Upload from android gallery to Server

from the CommonsWare Community archives

At June 9, 2020, 5:46am, brainy15mca asked:

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


At June 9, 2020, 10:42am, mmurphy replied:

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.


At June 10, 2020, 4:01pm, brainy15mca replied:

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


At June 10, 2020, 4:11pm, brainy15mca replied:

also if you want I can share mine Web Service API


At June 10, 2020, 5:39pm, mmurphy replied:

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


At June 10, 2020, 5:57pm, brainy15mca replied:

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


At June 10, 2020, 6:46pm, mmurphy replied:

You might consider running an experiment:

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.


At June 10, 2020, 6:51pm, brainy15mca replied:

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