lingochamp / okdownload

A Reliable, Flexible, Fast and Powerful download engine.
Apache License 2.0
5.19k stars 776 forks source link

不需要断点续传的单文件下载场景,可使用以下替代方案试一试 #507

Open wxw-9527 opened 9 months ago

wxw-9527 commented 9 months ago

项目实现版本更新功能时,测试发现系统提供的DownloadManager API部分机型在内网环境下无法获取文件长度,返回值始终为-1,导致文件下载失败。集成OkDownload后,发现多线程下载时合并文件偶发性失败,部分设备偶发下载进度卡在100%,taskEnd方法不回调。

鉴于需求比较简单,决定放弃集成OkDownload,采用OkHttp+Retrofit+okio实现简单的文件下载场景,其他有类似需求的可以参考一下。

1、创建Service
interface DownloadService {

        @Streaming
        @GET
        fun downloadFile(@Url fileUrl: String): Observable<ResponseBody>
}

2、下载文件
val disposable = mRetrofit?.create<DownloadService>()
            ?.downloadFile(url)
            ?.compose(schedulersTransformer())
            ?.subscribe(
                { responseBody ->
                    // 创建一个文件
                    val file = File(PATH + fileName)
                    val writtenToDisk = writeResponseBodyToDisk(responseBody, file)
                    Timber.tag("DownloadUtil").d("File download was a success? $writtenToDisk")
                    if (writtenToDisk && file.isFile && file.exists()) {
                        // TODO: 文件下载成功
                    }
                },
                { e ->
                    Timber.tag("DownloadUtil").e(e)
                }
            )

3、将文件写入本地
private fun writeResponseBodyToDisk(body: ResponseBody, file: File): Boolean {
        return try {
            // 使用OKio的sink和buffer方法来写文件
            file.sink().buffer().use { sink ->
                sink.writeAll(body.source())
            }
            true
        } catch (e: Exception) {
            Timber.tag("DownloadUtil").e(e)
            false
        }
    }

大致就是以上的代码,Retrofit实例一般项目中应该都有现成的单例对象,可以直接拿来用。