android– 使用Retrofit暂停和恢复下载

android– 使用Retrofit暂停和恢复下载,第1张

概述我使用本教程在我的应用程序中实现下载文件:https://www.learn2crack.com/2016/05/downloading-file-using-retrofit.html问题是如果互联网速度很慢或网络即使一秒钟波动,下载也会永久停止.是否有某种方式应用程序可以检测到互联网不活动(连接但实际上网络不工作),然后暂停下载并恢

我使用本教程在我的应用程序中实现下载文件:https://www.learn2crack.com/2016/05/downloading-file-using-retrofit.html

问题是如果互联网速度很慢或网络即使一秒钟波动,下载也会永久停止.是否有某种方式应用程序可以检测到互联网不活动(连接但实际上网络不工作),然后暂停下载并恢复互联网正常.

或者一些替代方案,这样用户不会感到沮丧?

解决方法:

我今天也遇到了这个问题,并没有找到任何好的解决方案,可以立即实现下载简历,进度通知和BufferedSink用于快速nio *** 作.

这就是使用Retrofit2和RxJava2的方法.代码在Kotlin for AndroID中可见,但它可以很容易地移植到纯JVM:只是摆脱AndroIDSchedulers

代码可能包含错误,因为它是在短时间内从头开始编写的,并且几乎没有经过测试.

import com.Google.gson.GsonBuilderimport io.reactivex.Observableimport io.reactivex.ObservableEmitterimport io.reactivex.ObservableOnSubscribeimport io.reactivex.androID.schedulers.AndroIDSchedulersimport io.reactivex.functions.Consumerimport io.reactivex.functions.Functionimport io.reactivex.schedulers.Schedulersimport okhttp3.OkhttpClIEntimport okhttp3.ResponseBodyimport okio.Bufferimport okio.BufferedSinkimport okio.ForwardingSourceimport okio.Okioimport org.slf4j.LoggerFactoryimport retrofit2.Responseimport retrofit2.Retrofitimport retrofit2.converter.gson.GsonConverterFactoryimport retrofit2.http.GETimport retrofit2.http.headerimport retrofit2.http.Streamingimport retrofit2.http.Urlimport java.io.fileimport java.io.IOExceptionimport java.util.concurrent.ConcurrentHashMapimport java.util.regex.Patternclass fileDownloader(val baseUrl: String) {    private val log = LoggerFactory.getLogger(fileDownloader::class.java)    private val expectedfileLength = ConcurrentHashMap<String, Long>()    private val eTag = ConcurrentHashMap<String, String>()    private val APIChecker: fileDownloaderAPI    init {        APIChecker = Retrofit.Builder()                .baseUrl(baseUrl)                .clIEnt(OkhttpClIEnt())                .addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenIEnt().create()))                .build()                .create(fileDownloaderAPI::class.java)    }    /**     *     * @return file Observable     */    fun download(            urlPath: String,            file: file,            dlProgressConsumer: Consumer<Int>): Observable<file> {        return Observable.create(ObservableOnSubscribe<file> {            val downloadobservable: Observable<Int>            if (file.exists() &&                    file.length() > 0L &&                    file.length() != expectedfileLength[file.name]                    ) {                /**                 * Try to get rest of the file according to:                 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.HTML                 */                downloadobservable = APIChecker.downloadfile(                        urlPath,                        "bytes=${file.length()}-",                        eTag[file.name] ?: "0"                ).flatMap(                        DownloadFunction(file, it)                )            } else {                /**                 * Last time file was fully downloaded or not present at all                 */                if (!file.exists())                    eTag[file.name] = ""                downloadobservable = APIChecker.downloadfile(                        urlPath,                        eTag[file.name] ?: "0"                ).flatMap(                        DownloadFunction(file, it)                )            }            downloadobservable                    .observeOn(AndroIDSchedulers.mainThread())                    .subscribe(dlProgressConsumer)        }).subscribeOn(Schedulers.io())                .observeOn(AndroIDSchedulers.mainThread())    }    private inner class DownloadFunction(            val file: file,            val fileEmitter: ObservableEmitter<file>    ) : Function<Response<ResponseBody>, Observable<Int>> {        var contentLength = 0L        var startingByte = 0L        var endingByte = 0L        var totalBytes = 0L        var contentRangePattern = "bytes ([0-9]*)-([0-9]*)/([0-9]*)"        fun parseContentRange(contentRange: String) {            val matcher = Pattern.compile(contentRangePattern).matcher(contentRange)            if (matcher.find()) {                startingByte = matcher.group(1).tolong()                endingByte = matcher.group(2).tolong()                totalBytes = matcher.group(3).tolong()            }        }        var totalRead = 0L        var lastPercentage = 0        overrIDe fun apply(response: Response<ResponseBody>): Observable<Int> {            return Observable.create { subscriber ->                try {                    if (!response.isSuccessful) {                        /**                         * Including response 304 Not ModifIEd                         */                        fileEmitter.onError(IllegalStateException("Code: ${response.code()}, ${response.message()}; Response $response"))                        return@create                    }                    contentLength = response.body().contentLength()                    log.info("{}", response)                    /**                     * Receiving partial content, which in general means that download is resumed                     */                    if (response.code() == 206) {                        parseContentRange(response.headers().get("Content-Range"))                        log.deBUG("Getting range from {} to {} of {} bytes", startingByte, endingByte, totalBytes)                    } else {                        endingByte = contentLength                        totalBytes = contentLength                        if (file.exists())                            file.delete()                    }                    log.info("Starting byte: {}, ending byte {}", startingByte, endingByte)                    totalRead = startingByte                    eTag.put(file.name, response.headers().get("ETag"))                    expectedfileLength.put(file.name, totalBytes)                    val sink: BufferedSink                    if (startingByte > 0) {                        sink = Okio.buffer(Okio.appendingSink(file))                    } else {                        sink = Okio.buffer(Okio.sink(file))                    }                    sink.use {                        it.writeall(object : ForwardingSource(response.body().source()) {                            overrIDe fun read(sink: Buffer, byteCount: Long): Long {                                val bytesRead = super.read(sink, byteCount)                                totalRead += bytesRead                                /**                                 * May not wok good if we get some shit from the mIDdle of the file,                                 * though that's not the case of this function, as we plan only to                                 * resume downloads                                 */                                val currentPercentage = (totalRead * 100 / totalBytes).toInt()                                if (currentPercentage > lastPercentage) {                                    val progress = "$currentPercentage%"                                    lastPercentage = currentPercentage                                    subscriber.onNext(currentPercentage)                                    log.deBUG("Downloading {} progress: {}", file.name, progress)                                }                                return bytesRead                            }                        })                    }                    subscriber.onComplete()                    fileEmitter.onNext(file)                    fileEmitter.onComplete()                } catch (e: IOException) {                    log.error("Last percentage: {}, Bytes read: {}", lastPercentage, totalRead)                    fileEmitter.onError(e)                }            }        }    }    interface fileDownloaderAPI {        @Streaming @GET        fun downloadfile(                @Url fileUrl: String,                @header("if-none-match") eTag: String        ): Observable<Response<ResponseBody>>        @Streaming @GET        fun downloadfile(                @Url fileUrl: String,                // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.HTML#sec14.35                @header("Range") bytesRange: String,                // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.HTML#sec14.27                @header("If-Range") eTag: String        ): Observable<Response<ResponseBody>>    }}

然后在您想要的地方使用它

    val fileDownloader = fileDownloader("http://wwww.example.com")    fileDownloader.download(            "/huge-vIDeo.mkv",            file("file-where-I-will-save-this-vIDeo.mkv"),            Consumer { progress ->                updateProgressNotificatuin()            }    ).subscribe({        log.info("file saved at path {}", it.absolutePath)    },{        log.error("Download error {}", it.message, it)    },{        log.info("Download completed")    })

此示例中使用的依赖项:

dependencIEs {    compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.1"    compile 'io.reactivex.rxjava2:rxandroID:2.0.1'    compile 'com.squareup.retrofit2:retrofit:2.2.0'    compile 'com.squareup.retrofit2:converter-gson:2.2.0'    compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'    compile 'com.Google.code.gson:gson:2.7'    compile 'org.slf4j:slf4j-api:1.7.25'}
总结

以上是内存溢出为你收集整理的android – 使用Retrofit暂停和恢复下载全部内容,希望文章能够帮你解决android – 使用Retrofit暂停和恢复下载所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1118360.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-29
下一篇2022-05-29

发表评论

登录后才能评论

评论列表(0条)

    保存