ssseasonnn / RxDownload

A multi-threaded download tool written with RxJava and Kotlin
Apache License 2.0
4.14k stars 612 forks source link

Realtime download progress #305

Closed ghost closed 4 years ago

ghost commented 4 years ago

I successfully retrieving download data with TaskRecord, but need to get realtime update listener from other activities. Download starts from "BrowserActivity.kt" and "DownloadsActivity.kt" act as a list of downloaded progress. Any listener to handle that? Thank you

ezgif-3-755b14e359eb

ssseasonnn commented 4 years ago

Use the same task to re-subscribe in different activities.

ghost commented 4 years ago

Ok I found you've implemented on demo

ghost commented 4 years ago

Sorry, I reopen this case. How to retry after download failed in specific times? Also, I need to catch when failed download returns "Chunked can not get totalSize!", this happened on certain websites

ssseasonnn commented 4 years ago

This means that your url does not support breakpoint download, and its transmission method is Chunked. In this case, we cannot get the totalSize

ssseasonnn commented 4 years ago

When the download fails, restart it.

ghost commented 4 years ago

ok.. last one about yasha library it's possible to make an action with data source items inside renderStatus? I use BottomSheetDialog and need to remove the item from recycler

ssseasonnn commented 4 years ago

you can render a empty status item, or setState = null

ghost commented 4 years ago

Can you provide an example? I'm stuck with this

private fun renderStatus(scope: YashaScope<DownloadAdapterItem>, it: Status, context: Context) {
  scope.apply {
    when(it) {
      is Completed -> {
         bottomSheetDialog.apply {
            show()
            tv_delete.apply {
                delete()
                -- remove the item from recycler like datasource.removeItem() does --
                dismiss()
            }
         }
      }
    }
  }
}

Thank you

ssseasonnn commented 4 years ago

I understand, you can only use dataSource to remove items, no direct action

ssseasonnn commented 4 years ago

Maybe you can use livedata to send an event and then listen in the activity to delete this item

ghost commented 4 years ago

This means that your url does not support breakpoint download, and its transmission method is Chunked. In this case, we cannot get the totalSize

I use isChunked from status to catch those errors. but sometime crashes on certain devices

 is Normal, is Started, is Failed, is Downloading -> {
        if (it.progress.isChunked) {
            taskManager.stop()
            Handler().postDelayed({
              taskManager.start()
            }, 3000)
        }
}

image image

ssseasonnn commented 4 years ago

Got it, fix it later

ghost commented 4 years ago

image image

ghost commented 4 years ago

Please add setOngoing to prevent notification swipe while the download is running on NotificationCompat. Maybe you need to define Quadruple to set "setOngoing" value inside SimpleNotificationCreator

ghost commented 4 years ago

any progress? hope I can disable breakpoint like other download manager libraries on github does. or at least throwing those errors

ssseasonnn commented 4 years ago

fixed, 1.1.2

ghost commented 4 years ago

I have added this to catch RxJava global errors in Application

RxJavaPlugins.setErrorHandler {
      if (it is UndeliverableException) {
        //do nothing
      } else {
        it.log()
      }
    }

But when i pause/stop the download, sometimes i got error "Socket Closed" Any solution?

ghost commented 4 years ago
java.lang.IllegalStateException: Chunked can not get percent!
        at zlc.season.rxdownload4.Progress.percent(Progress.kt:33)
        at com.usamin.app.adapter.DownloadAdapterItem.renderStatus(DownloadsAdapterSource.kt:92)
        at com.usamin.app.adapter.DownloadAdapterItem.access$renderStatus(DownloadAdapterItem:70)

tv_percent.text = it.progress.percentStr()

https://github.com/ssseasonnn/RxDownload/blob/21e4e66602f150bd38c7464fe2e96cdbd4c79080/rxdownload4/src/main/java/zlc/season/rxdownload4/Progress.kt#L33

ssseasonnn commented 4 years ago

When you display progress on the UI, first determine isChunked. If it is true, set the indeterminate property of the progressbar to true

ssseasonnn commented 4 years ago

Because chunked download can not get totalSize, so you can not show real progress

ghost commented 4 years ago

ok, i fixed by adding

if(!it.progress.isChunked) {
          tv_percent.text = it.progress.percentStr()
        }

now the main problem with RxJava error. Sometimes got socket closed, response is null, etc I have added this but still not working image

ghost commented 4 years ago

I ended by adding try catch for every progress, using isChunked still doesn't help, Better to set it to 0 first, rather than throwing an Exception

ghost commented 4 years ago
java.net.SocketException: Socket closed
        at com.google.android.gms.org.conscrypt.NativeCrypto.SSL_read(:com.google.android.gms@200616020@20.06.16 (040406-296104215):-2)
        at com.google.android.gms.org.conscrypt.NativeSsl.read(:com.google.android.gms@200616020@20.06.16 (040406-296104215):3)
        at com.google.android.gms.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream.read(:com.google.android.gms@200616020@20.06.16 (040406-296104215):7)
        at okio.InputStreamSource.read(Okio.kt:93)
        at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
        at okio.RealBufferedSource.read(RealBufferedSource.kt:188)
        at okhttp3.internal.http1.Http1ExchangeCodec$AbstractSource.read(Http1ExchangeCodec.kt:349)
        at okhttp3.internal.http1.Http1ExchangeCodec$FixedLengthSource.read(Http1ExchangeCodec.kt:386)
        at okhttp3.internal.connection.Exchange$ResponseBodySource.read(Exchange.kt:276)
        at okio.RealBufferedSource.read(RealBufferedSource.kt:188)
        at okio.ForwardingSource.read(ForwardingSource.kt:29)
        at retrofit2.OkHttpCall$ExceptionCatchingResponseBody$1.read(OkHttpCall.java:288)
        at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:158)
        at java.io.InputStream.read(InputStream.java:101)
        at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:152)
        at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:123)
        at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:62)
        at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:53)
        at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:109)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:661)
        at io.reactivex.internal.operators.flowable.FlowableGenerate.subscribeActual(FlowableGenerate.java:52)
        at io.reactivex.Flowable.subscribe(Flowable.java:14935)
        at io.reactivex.Flowable.subscribe(Flowable.java:14882)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap:282)
        at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:668)
        at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129)
        at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68)
        at io.reactivex.internal.operators.flowable.FlowableFromObservable$SubscriberObserver.onNext(FlowableFromObservable.java:54)
        at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
        at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:47)
        at io.reactivex.Observable.subscribe(Observable.java:12284)
        at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
        at java.lang.Thread.run(Thread.java:764)