首页 > 解决方案 > 在 kotlin 中上传文件时出现内存不足错误

问题描述

我遇到以下 OOM 错误

  Version Name: 1.0
Version Code: 1
Android Version: 8.1.0
Device: Xiaomi (Redmi 6A)
java.lang.RuntimeException: An error occurred while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:353)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
    at java.util.concurrent.FutureTask.run(FutureTask.java:271)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
    at java.lang.Thread.run(Thread.java:764)
Caused by: java.lang.OutOfMemoryError: Failed to allocate a 301989896 byte allocation with 25149440 free bytes and 106MB until OOM, max allowed footprint 182027488, growth limit 268435456
    at java.util.Arrays.copyOf(Arrays.java:3260)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:125)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:660)
    at java.lang.StringBuffer.append(StringBuffer.java:381)
    at com.sbs16.ensofia.manager.ContentUploadTask.doInBackground(ContentUploadTask.kt:95)
    at com.sbs16.ensofia.manager.ContentUploadTask.doInBackground(ContentUploadTask.kt:15)
    at android.os.AsyncTask$2.call(AsyncTask.java:333)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    ... 4 more

这是我的方法

class ContentUploadTask(private val callback: UploadCallback) :
    AsyncTask<String, Void, String>() {

    override fun doInBackground(vararg params: String): String? {
        val conn: HttpURLConnection
        val dos: DataOutputStream
        val inStream: DataInputStream

        val fileName = params[0]
        val hsUrl = params[1]
        val accessToken = params[2]

        var bytesRead: Int
        var bytesAvailable: Int
        var bufferSize: Int

        val buffer: ByteArray

        val maxBufferSize = 1 * 1024 * 1024

        var responseFromServer: String? = null

        val urlString = "$hsUrl${ContentManager.URI_PREFIX_CONTENT_API}upload?access_token=$accessToken"

        try {
            val fileInputStream = FileInputStream(File(fileName))

            val url = URL(urlString)

            conn = url.openConnection() as HttpURLConnection
            conn.doInput = true
            conn.doOutput = true
            conn.useCaches = false
            conn.requestMethod = "POST"

            // TODO: Handle other file types
            val mimeType = ContentUtils.getMimeType(fileName)
            if (mimeType.startsWith("image/")) {
                val imageInfo = ContentUtils.getImageInfoFromFile(fileName)
                conn.setRequestProperty("Content-type", imageInfo.mimetype)
                conn.setRequestProperty("Content-length", "" + (imageInfo.size))
            }

            conn.connect()

            dos = DataOutputStream(conn.getOutputStream())

            // create a buffer of maximum size
            bytesAvailable = fileInputStream.available()
            bufferSize = Math.min(bytesAvailable, maxBufferSize)
            buffer = ByteArray(bufferSize)

            // read file and write it into form...
            bytesRead = fileInputStream.read(buffer, 0, bufferSize)

            while (bytesRead > 0) {
                dos.write(buffer, 0, bufferSize)
                bytesAvailable = fileInputStream.available()
                bufferSize = Math.min(bytesAvailable, maxBufferSize)
                bytesRead = fileInputStream.read(buffer, 0, bufferSize)
            }

            // close streams
            fileInputStream.close()
            dos.flush()
            dos.close()

            // Read the SERVER RESPONSE
            val status = conn.responseCode
            if (status == 200) {
                val inps = conn.inputStream
                val b = StringBuffer()
                /*
                var ch: Int
                while ((ch = inps.read()) != -1) {
                    b.append(ch.toChar())
                }*/

                var ch: Int = inps.read()
                while (ch != -1) {
                    b.append(ch.toChar())
                }

                responseFromServer = b.toString()
                inps.close()
            } else {
                Log.e("AMIRA8888", "Error: Upload returned $status status code")
                return null
            }

        } catch (e: Exception) {
            Log.e("AMIRA8888", "Error: " + e.message)
        }

        return responseFromServer
    }

    override fun onPostExecute(s: String?) {
        //callback.onUploadComplete(if (s == null) null else JsonUtils.toContentResponse(s))
        Log.e("AMIRA8888", "response: " + s)

    }
}

interface UploadCallback {

    fun onUploadComplete(uploadResponse: ContentResponse)
}

标签: androidkotlinout-of-memory

解决方案


推荐阅读