Fetch icon indicating copy to clipboard operation
Fetch copied to clipboard

Very Slow Download Speed

Open Soft-Buddy opened this issue 5 months ago • 0 comments

I migrated from using basic HttpUrlConnection to Fetch. But I've seen a huge download speed loss. For reference, I have 50mbps connection

Here's my code : My old approach : (hardly takes few seconds to download) OnlinePdfLoader.kt

import android.app.Activity
import android.content.Context
import android.util.Log
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL

@Suppress("unused")
class OnlinePdfLoader(private val activity: Activity) {
    fun resolveFile(
        target: String,
        onDownloaded: (file: File) -> Unit,
        onDownloadFailed: (error: String) -> Unit
    ) {
        Thread {
            var file: File? = null
            var inputStream: InputStream? = null
            var outputStream: FileOutputStream? = null
            try {
                val url = URL(target)
                val fileName = getFileName(url)
                val directory =
                    File(activity.filesDir.absolutePath + File.separator + DIRECTORY_TEMP)
                file = File(directory, fileName)
                if (file.exists()) {
                    activity.runOnUiThread {
                        onDownloaded(file)
                    }
                    return@Thread
                }
                val connection = url.openConnection() as HttpURLConnection
                connection.connect()
                inputStream = connection.inputStream

                if (!directory.exists()) {
                    val success = directory.mkdirs()
                    if (!success) {
                        throw Exception(
                            String.format(
                                "Error creating directory",
                                directory.name
                            )
                        )
                    }
                }
                outputStream = FileOutputStream(file)
                val bufferSize = 4096
                val buffer = ByteArray(bufferSize)
                var bytesRead: Int
                var totalBytesRead: Long = 0
                while ((inputStream.read(buffer).also { bytesRead = it }) != -1) {
                    outputStream.write(buffer, 0, bytesRead)
                    totalBytesRead += bytesRead.toLong()
                }
                activity.runOnUiThread {
                    onDownloaded(file)
                }
            } catch (e: Exception) {
                if (file != null && file.exists()) {
                    file.delete()
                }
                e.printStackTrace()
                e.message?.let {
                    activity.runOnUiThread {
                        onDownloadFailed(it)
                    }
                }
            } finally {
                try {
                    inputStream?.close()
                    outputStream?.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }.start()
    }

    fun resolveStream(
        target: String,
        onResolved: (inputStream: InputStream) -> Unit,
        onError: (error: String) -> Unit
    ) {
        Thread {
            var inputStream: InputStream? = null
            val url = URL(target)
            try {
                val connection = url.openConnection() as HttpURLConnection
                connection.connect()
                inputStream = connection.inputStream
                activity.runOnUiThread {
                    onResolved(inputStream)
                }
            } catch (e: Exception) {
                e.printStackTrace()
                e.message?.let {
                    activity.runOnUiThread {
                        onError(it)
                    }
                }
            } finally {
                try {
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }.start()
    }

    companion object {
        fun isDownloaded(context: Context, url: String): Boolean {
            val fileName = getFileName(URL(url))
            val directory =
                File(context.filesDir.absolutePath + File.separator + DIRECTORY_TEMP)
            val file = File(directory, fileName)
            return file.exists()
        }

        fun getFileName(url: URL): String {
            val urlString = url.toString()
            return urlString.substring(urlString.lastIndexOf('/') + 1)
        }
    }

    interface DownloadListener {
        fun onDownloadComplete(filePath: String)

        fun onDownloadFailed(message: String, logs: String)
    }
}

New Approach : (Takes almost a minute)

val fetch = getInstance(
            FetchConfiguration.Builder(this)
                .setHttpDownloader(OkHttpDownloader())
                .build()
        )
val request = Request(url, file.absolutePath)
                    request.priority = Priority.HIGH
                    request.networkType = NetworkType.ALL
                    circularProgress.setOnClickListener {
                        fetch.cancel(request.id)
                    }
                    fetch.enqueue(request, {
                        var fetchListener: FetchListener? = null
                        fetchListener = object : FetchListener {
                            override fun onQueued(download: Download, waitingOnNetwork: Boolean) {}

                            override fun onCompleted(d: Download) {
                                isDownloading = false
                                Toast.makeText(context, "Download Complete", Toast.LENGTH_SHORT).show()
                                mode.text = "Downloaded"
                                download.setImageResource(R.drawable.ic_delete)
                                circularProgress.visibility = View.GONE
                                download.visibility = View.VISIBLE
                                fetch.removeListener(fetchListener!!)
                            }

                            override fun onPaused(download: Download) { }

                            override fun onProgress(
                                download: Download,
                                etaInMilliSeconds: Long,
                                downloadedBytesPerSecond: Long
                            ) {

                            }

                            override fun onResumed(download: Download) {
                            }

                            override fun onStarted(
                                download: Download,
                                downloadBlocks: List<DownloadBlock>,
                                totalBlocks: Int
                            ) {

                            }

                            override fun onWaitingNetwork(download: Download) {

                            }

                            override fun onAdded(download: Download) {

                            }

                            override fun onCancelled(dw: Download) {
                                File(dw.file).delete()
                                isDownloading = false
                                mode.text = "Online"
                                circularProgress.visibility = View.GONE
                                download.visibility = View.VISIBLE
                                fetch.removeListener(fetchListener!!)
                            }

                            override fun onRemoved(download: Download) {
                            }

                            override fun onDeleted(download: Download) {
                            }

                            override fun onDownloadBlockUpdated(
                                download: Download,
                                downloadBlock: DownloadBlock,
                                totalBlocks: Int
                            ) {

                            }

                            override fun onError(
                                dw: Download,
                                error: com.tonyodev.fetch2.Error,
                                throwable: Throwable?
                            ) {
                                isDownloading = false
                                circularProgress.visibility = View.GONE
                                download.visibility = View.VISIBLE
                                mode.text = "Online"
                                Toast.makeText(context, "Download Failed. $it", Toast.LENGTH_SHORT).show()
                                fetch.removeListener(fetchListener!!)
                            }
                        }
                        fetch.addListener(fetchListener)
                    }, { error ->
                        Toast.makeText(
                            context,
                            "Error enqueuing download request. $error",
                            Toast.LENGTH_SHORT
                        ).show()
                    })
                    

Demo Video :

Old Approach- https://github.com/user-attachments/assets/5dd25a5b-f520-41f5-80f7-554e17599b5d

New Approach - https://github.com/user-attachments/assets/23eb3ec5-2669-4ed2-94ce-729122da8422

Soft-Buddy avatar Sep 14 '24 19:09 Soft-Buddy