Jak nahrát velké soubory na server pomocí retrofit vícedílné

0

Otázka

Mám žádost, která funguje dobře v postman:

enter image description here

a já se snažím, aby to s Retrofit. V obecné velikost souboru bude >500MB. Udělal jsem takový způsob nahrávání:

fun uploadFile(file:File) {

        val client = OkHttpClient().newBuilder()
            .build()
        val mediaType: MediaType? = "text/plain".toMediaTypeOrNull()
        val body: RequestBody = MultipartBody.Builder().setType(MultipartBody.FORM)
            .addFormDataPart(
                "data", file.name,
                file.asRequestBody()
            )
            .build()
        val request: Request = Request.Builder()
            .url("https://..../upload.php")
            .method("POST", body)
            .build()
        val response: okhttp3.Response = client.newCall(request).execute()

       println(response.message)
    }

ale musím mít soubor pro nahrání. Mohu vytvořit dočasný soubor s takovým způsobem:

val path = requireContext().cacheDir
val file = File.createTempFile(
    name ?: "",
    fileUri.lastPathSegment,
    path
)
val os = FileOutputStream(file)
os.write(string)
os.close()

ale já obvykle dostávají outOfMemoryException. Také jsem přidal do AndroidManifest.xml haldy param:

android:largeHeap="true"

ale to mě nepomohlo vůbec během temp soubor vytváří. Nevím, jak pošťák nahrávání souborů, ale obecně se mi podařilo nahrát s jeho pomocí souboru s velikosti cca 600Mb. Mohu také snížit vybraný soubor s kousky:

val data = result.data
data?.let {
      val fileUri = data.data
      var name: String? = null
      var size: Long? = null
      fileUri.let { returnUri ->
            contentResolver?.query(returnUri!!, null, null, null, null)
      }?.use { cursor ->
            val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
            val sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE)

            cursor.moveToFirst()
            name = cursor.getString(nameIndex)
            size = cursor.getLong(sizeIndex)
       }


val inputStream: InputStream? = fileUri?.let { it1 ->
    contentResolver.openInputStream(
        it1
    )
}

val fileData = inputStream?.readBytes()
val mimeType = fileUri.let { returnUri ->
returnUri.let { retUri ->
    if (retUri != null) {
           contentResolver.getType(retUri)
    }
}
}


fileData?.let {
       val MAX_SUB_SIZE = 4194304 // 4*1024*1024 == 4MB
       var start = 0 // From 0
       var end = MAX_SUB_SIZE // To MAX_SUB_SIZE bytes
       var subData: ByteArray // 4MB Sized Array

       val max = fileData.size
       if (max > 0) {
           while (end < max) {
                subData = fileData.copyOfRange(start, end)
                start = end
                end += MAX_SUB_SIZE
                if (end >= max) {
                    end = max
                }
                                
                println("file handling" + subData.size)



        }
     end-- // To avoid a padded zero
     subData = fileData.copyOfRange(start, end)
     println("file handling" + subData.size)
     }
   }
}

všechny akce budou provedeny v:

 private val filesReceiver =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == Activity.RESULT_OK) {

             }
         }

takže nebudu mít žádnou cestu k souboru v normálním způsobem. Každopádně si myslím, že jsem udělal něco špatně.

AKTUALIZACE

teď mám jako nahrávání souborů z inputStream:

 private fun doSomeNetworkStuff(file:InputStream, name:String) {
        GlobalScope.launch(Dispatchers.IO) {
            val client = OkHttpClient()
                .newBuilder()
                .protocols(listOf(Protocol.HTTP_1_1))
                .connectTimeout(10, TimeUnit.MINUTES)
                .readTimeout(10, TimeUnit.MINUTES)
                .build()
            val mediaType: MediaType? = "text/plain".toMediaTypeOrNull()
            val body: RequestBody = MultipartBody.Builder().setType(MultipartBody.FORM)
                .addFormDataPart(
                    "data", name,
                    file.readBytes().toRequestBody(mediaType)
                )
                .build()
            val request: Request = Request.Builder()
                .url("https://.../upload.php")
                .method("POST", body)
                .build()

            val response: Response = client.newCall(request).execute()

            println(response.body)
        }
    }

a přijímat taková chyba:

java.lang.OutOfMemoryError: Failed to allocate a 173410912 byte allocation with 25165824 free bytes and 89MB until OOM, max allowed footprint 199761800, growth limit 268435456

ale můžu nahrát s tímto kodexem soubor s velikost cca 90 mb

android
2021-11-24 05:56:49
2

Nejlepší odpověď

1

Retrofit vícedílné věci, má člen, který bere Uri pro žádost těla.

Zkuste použít jeden pro Soubor instance.

2021-11-24 07:53:27

můžete objasnit, pls, které personál, protože jsem viděl tuto otázku stackoverflow.com/questions/34562950/... a používají zaměstnanci od něj
Andrew

Viděl jsi somerhing pro uri? Pro vstupní proud?
blackapps

Google pro inputstreamrequestbody.
blackapps

Snažil jsem se použít vstupní proud jak jste řekl, ale s bajtové pole využití, a můj způsob nahrávání selže na velikost souboru > 90mb, můžete se podívat na mou otázku upd pls?
Andrew

Udělal jsem jen říci, používat uri. Zdá se, že ty to dělat nebudeš. Neměli byste používat bajtové pole. Nebo vstupního proudu. No... Ne tímto způsobem.
blackapps

možná můžete přidat nějaký vzorek, protože jsem to udělal, jako jste pochopil, možná znáte lepší, to, že mě?) protože jsem nenašel žádné zmínky o uri requestbody
Andrew

0

Už jste nastavit log ve loggingInterceptor nebo restadapter ?
pokud ano, pak zkuste nastavit NIC.

2021-11-24 06:14:28

to je již hotovo
Andrew

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................