Fetch
Fetch copied to clipboard
Very Slow Download Speed
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