1

I have tried to upload large videos to server using Restful APIs with the help of Retrofit. But each and every time I unable to upload it via this scenario. This works fine for small videos around 100 MBs but its not eligible for larger than 300 MBs.

  1. What is needs to upload very large files to server? Ans : I am creating Web Series playing application like(Netflix, Amazon Prime, etc) and there is also a Administrator role. Admin can upload web series via mobile and its possibly very large in size around 400 MB to 1 GB.

Process I done : simply I create foreground service and bind notification titled "Video is uploading". Because this task is very long time taken so I need to do that. After that I making API call inside from this service.

Now the actual exception happens while I received video from gallery and uploading to server then exception arise. Exception : java.lang.OutOfMemoryError: Failed to allocate a 392080272 byte allocation with 25165824 free bytes and 318MB until OOM, target footprint 227699960, growth limit 536870912

 private var call: Call<ResponseBody?>? = null
    private fun callAPI(data: VideoUpload) {
        val str = "text/plain"
        val videoFile = RequestBody.create("*/*".toMediaTypeOrNull(), data.file)
        val videoBody = MultipartBody.Part.createFormData("episode_file", data.file.name, videoFile)
        val apiInterface = RetrofitClient.getRetrofitInstance(applicationContext)!!.create(ApiInterface::class.java)
        val listener = this
        val context = this
        try {
            System.gc()
            ioScope.launch {
                
                call = apiInterface.addEpisode(
                    videoBody,
                    RequestBody.create(str.toMediaTypeOrNull(), data.episodeName),
                    RequestBody.create(str.toMediaTypeOrNull(), data.episodeDuration),
                    RequestBody.create(str.toMediaTypeOrNull(), data.episodeDesc),
                    RequestBody.create(str.toMediaTypeOrNull(), data.webSeriesId)
                )
                APIResponse.callRetrofitCustom<ResponseBody>(call, AppConstants.ADD_EPISODE, context, listener)
            }
        } catch (e: IOException) {
            Log.e(TAG, "callAPI: ${e.localizedMessage}")
        }
    }
/*  Background young concurrent copying GC freed 8(47KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 223MB/223MB, paused 233us total 395.877ms*/

Please provide required solution. Thanks in advance.

a_local_nobody
  • 7,947
  • 5
  • 29
  • 51
  • You are putting that big file in memory first. That causes for an out of memory error. Dont put files in memory first. Just read chuncks from disk and write those to the server. Work wit an InputStreamRequestBody. – blackapps Mar 05 '21 at 11:43
  • A related question: https://stackoverflow.com/questions/22542230/how-to-post-inputstream-as-the-body-of-a-request-in-retrofit – Robert Mar 05 '21 at 11:47

2 Answers2

0

This is an example of declaration of a function which uses multipart/form-data to send a large block of data (binary data) to a server using Retrofit:

    @Multipart
    @POST("SendData")
    suspend fun sendData(@Part("sessionId") sessionId: RequestBody, @Part("dataId") id: RequestBody, @Part("categoryId") categoryId: RequestBody?, @Part data: MultipartBody.Part): Response<Void>

And it is used in the following method:

    private suspend fun sendLargeData(sessionId: UUID, data: ByteArray) {
    
            try {
                val data_part = data.toRequestBody("multipart/form-data".toMediaTypeOrNull())
                val data_multi_part =
                    MultipartBody.Part.createFormData("data buffer", p.description, data_part)
                val sessionId_part =
                    sessionId.toString().toRequestBody("multipart/form-data".toMediaTypeOrNull())
                val id_part = p.id.toString().toRequestBody("multipart/form-data".toMediaTypeOrNull())
                val categoryId_part =
                    p.categoryId?.toString()?.toRequestBody("multipart/form-data".toMediaTypeOrNull())
                val response = api.sendData(sessionId_part, id_part, categoryId_part, data_multi_part)
                if (!response.isSuccessful) {
//Error here
    
                    response.errorBody()?.close()
                }
    
            } catch (e: Exception) {
    
                //show error
            }
    
         
        }
Sergiob
  • 838
  • 1
  • 13
  • 28
0

In the manifest try these lines
android:largeHeap="true"
and
android:hardwareAccelerated="false"

Usama Altaf
  • 90
  • 1
  • 4
  • 23
  • Thanks for your response. I already added both this things to manifest file. But still facing exception. – Rakesh Parmar Mar 05 '21 at 11:31
  • hey checkout this answer I think it is helpful for you I know the answer is for downloading purpose from retrofit but this will help you for sure https://stackoverflow.com/a/44244157/11647620 – Usama Altaf Mar 05 '21 at 11:36