
我使用本教程在我的应用程序中实现下载文件: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暂停和恢复下载所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)