Giter Site home page Giter Site logo

rxdownload's Introduction

RxDownload

A multi-threaded download tool written with RxJava and Kotlin

Read this in other languages: 中文English, Changelog 

Prepare

  • Add jitpack repo:

    maven { url 'https://jitpack.io' }
    
  • Add RxDownload dependency:

    //Load on demand
    implementation "com.github.ssseasonnn.RxDownload:rxdownload4:1.1.4"
    implementation "com.github.ssseasonnn.RxDownload:rxdownload4-manager:1.1.4"
    implementation "com.github.ssseasonnn.RxDownload:rxdownload4-notification:1.1.4"
    implementation "com.github.ssseasonnn.RxDownload:rxdownload4-recorder:1.1.4"
    
    or: 
    //Add all dependencies of RxDownload4
    implementation "com.github.ssseasonnn:RxDownload:1.1.4"

Basic Usage

  • Start download:

    disposable = url.download()
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeBy(
                    onNext = { progress ->
                        //download progress
                        button.text = "${progress.downloadSizeStr()}/${progress.totalSizeStr()}"
                        button.setProgress(progress)
                    },
                    onComplete = {
                        //download complete
                        button.text = "Open"
                    },
                    onError = {
                        //download failed
                        button.text = "Retry"
                    }
            )    
  • Stop download:

    disposable.dispose()    
  • Get download file:

    val file = url.file()
    // or
    val file = task.file() 
    // use file...   
  • Delete download files:

    url.delete()
    // or
    task.delete() 

Task Manager

  • Get a TaskManager object:

    val taskManager = url.manager()
  • Subscribe to status update:

    //keep this tag for dispose
    val tag = taskManager.subscribe { status ->
        // Receive download status
        when (status) {
            is Normal -> {}
            is Started -> {}
            is Downloading -> {}
            is Paused -> {}
            is Completed -> {}
            is Failed -> {}
            is Deleted -> {}
        }
    }
        

    progress can be obtained from status, when status is Failed, you can get throwable from it, which is the reason for the failure.

  • Cancel status update subscription:

    //dispose tag
    taskManager.dispose(tag)
  • Start download:

    taskManager.start()
  • Stop download:

    taskManager.stop()
  • Delete download:

    taskManager.delete()
  • Get download file:

    val file = taskManager.file() 
    // use file...   

Task Recorder

  • Query single task:

     // Query task with url
     RxDownloadRecorder.getTask("url")
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeBy { TaskEntity ->
               // TaskEntity                        
           } 
  • Query a batch of tasks:

     // Query task with urls
     RxDownloadRecorder.getTaskList("url1","url2","url3")
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeBy { list ->
               // list of TaskEntity                        
           } 
  • Get a list of all downloads:

     RxDownloadRecorder.getAllTask()
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeBy { list ->
               //list of TaskEntity                        
           }
  • Query all download records for a state:

     // Query all Completed records
     RxDownloadRecorder.getAllTaskWithStatus(Completed())
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeBy { list ->
               //list of TaskEntity                        
           } 
  • Paging query download record list:

     RxDownloadRecorder.getTaskList(page, pageSize)
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeBy { list ->
               //list of TaskEntity                        
           }
  • Paging query list of download records in a certain state:

     // Get the list of pages that have been Completed
     RxDownloadRecorder.getTaskListWithStatus(Completed(), page, pageSize)
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeBy { list ->
               //list of TaskEntity                        
           }

    TaskEntity has a abnormalExit field, which is used to indicate whether the Task has paused by the APP forced close.

  • Start All:

     RxDownloadRecorder.startAll()
  • Stop All:

     RxDownloadRecorder.stopAll()
  • Delete All:

     RxDownloadRecorder.deleteAll()

License

Copyright 2019 Season.Zlc

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

rxdownload's People

Contributors

bharathmg avatar deishelon avatar dittopia-ai avatar ssseasonnn avatar vitusortner avatar xieqiupeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxdownload's Issues

批量下载

批量下载,怎么添加到数据库,能在列表显示出来?

请教一下,您是如何保证多线程下写入安全的

因为我也在做一个文件下载库
SimpleDownloader
因为SQLite并不支持并发写入,所以我在写入方法上加上synchronized,但是考虑到可能存在的效率问题,所以又把写入操作的参数放入message然后传到Handler消息队列中,结果在测试的时候发现虽然安全性保证,但写入效率更低。最后改为将文件分片,然后根据每个文件片的长度来判定断点下载的开始位置。

我学习了下您的代码,发现您没有对数据库的写入加锁也没有合并成事务而是直接操作,当任务线程增多(比如上百个)的情况下会不会有问题呢?想和您交流一下

should we throw a RuntimeException in getWhenFileExists function?

I saw the getWhenFileExists function as follow:

private Observable<DownloadType> getWhenFileExists(final String url) throws IOException {
    return getDownloadApi()
            .getHttpHeaderWithIfRange(TEST_RANGE_SUPPORT, getLastModify(url), url)
            .map(new Function<Response<Void>, DownloadType>() {
                @Override
                public DownloadType apply(Response<Void> resp) throws Exception {
                    if (Utils.serverFileNotChange(resp)) {
                        return getWhenServerFileNotChange(resp, url);
                    } else if (Utils.serverFileChanged(resp)) {
                        return getWhenServerFileChanged(resp, url);
                    } else if (Utils.requestRangeNotSatisfiable(resp)) {
                        return mFactory.url(url)
                                .fileLength(Utils.contentLength(resp))
                                .lastModify(Utils.lastModify(resp))
                                .buildRequestRangeNotSatisfiable();
                    } else {
                        throw new RuntimeException("unknown error");  //<==throwing a RuntimeException is somewhat weird
                    }
                }
            })
            .retry(new BiPredicate<Integer, Throwable>() {
                @Override
                public boolean test(Integer integer, Throwable throwable) throws Exception {
                    return retry(integer, throwable);
                }
            });
}

Throwing a RuntimeException to notify the subscriber is somewhat weird.
I suggest that we should add a UnableDownloadType class to indicate the http response cannot support downloading, and return a UnableDownloadType instance here. When we are processing DownloadType, if the download type is UnableDownloadType, we throw a specific Exception as like UnableDownloadException:

getDownloadType(url)
.flatMap(new Function<DownloadType, ObservableSource<DownloadStatus>>() {
    @Override
    public ObservableSource<DownloadStatus> apply(DownloadType downloadType) throws Exception {
        if (downloadType instanceof UnableDownloadType) {  //<==check the download type
            throw new UnableDownloadException(...)
        } else {
            downloadType.prepareDownload();
            return downloadType.startDownload();
        }
    }
})

关于 DataBaseHelper 的 readRecord 实现

我认为 DataBaseHelper 类中 readRecord 方法的实现不是很好。

现有方式

当数据库找不到相应数据,是直接调用 subscriber.onCompleted(),没有调用 subscriber.onNext() 方法。

会出现的问题

当对 RxDownload.getDownloadRecord() 返回的 Observable 对象使用 subscribe(new Action1() {...}) 方法订阅时,会无法触发 call() ,这样没办法很好地结合其它 Observable 做链式处理(map、concatMap指令等等)

想法

在 readRecord 方法中,增加 subscriber.onNext() 的调用,例如:

cursor = getReadableDatabase().rawQuery("select * from " + TABLE_NAME + " where " + "url=?", new String[]{url});
if (cursor.moveToNext()) {
    subscriber.onNext(Db.RecordTable.read(cursor));
    while (cursor.moveToNext()) {
        subscriber.onNext(Db.RecordTable.read(cursor));
    }
} else {
    subscriber.onNext(null);
}
subscriber.onCompleted();

下载未完成也会调用onCompleted

你好,我的需求是同时下载多个文件,每下完一个文件在数据库作记录,于是我onCompleted中记录该文件已下载,结果我发现数据库中的记录与下载的文件不一致。是我哪里操作不当吗?望大神指教。

关于使用前台下载方式遇到:rx.exceptions.MissingBackpressureException 错误

调用代码:

Subscription subscription = rxDownload.download(url, fileName, savePath)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<DownloadStatus>() {
                     @Override
                    public void onCompleted() {
                    //下载完成
                    ...
                    }

                    @Override
                    public void onError(Throwable e) {
                    //下载出错
                    ...
                    }

                    @Override
                    public void onNext(final DownloadStatus status) {
                    //下载状态
                    ...
                    }
                });

错误日志:

rx.exceptions.MissingBackpressureException
     at rx.internal.operators.OperatorObserveOn$ObserveOnSubscriber.onNext(OperatorObserveOn.java:160)
     at rx.internal.operators.OperatorUnsubscribeOn$1.onNext(OperatorUnsubscribeOn.java:52)
     at rx.internal.operators.OperatorSubscribeOn$1$1.onNext(OperatorSubscribeOn.java:53)
     at rx.observers.Subscribers$5.onNext(Subscribers.java:235)
     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onNext(OnSubscribeDoOnEach.java:101)
     at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onNext(OnSubscribeDoOnEach.java:101)
     at rx.internal.operators.OperatorMerge$MergeSubscriber.emitScalar(OperatorMerge.java:395)
     at rx.internal.operators.OperatorMerge$MergeSubscriber.tryEmit(OperatorMerge.java:355)
     at rx.internal.operators.OperatorMerge$InnerSubscriber.onNext(OperatorMerge.java:846)
     at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1$1.onNext(OperatorRetryWithPredicate.java:115)
     at rx.internal.operators.OperatorOnBackpressureLatest$LatestEmitter.emit(OperatorOnBackpressureLatest.java:165)
     at rx.internal.operators.OperatorOnBackpressureLatest$LatestEmitter.onNext(OperatorOnBackpressureLatest.java:131)
     at rx.internal.operators.OperatorOnBackpressureLatest$LatestSubscriber.onNext(OperatorOnBackpressureLatest.java:211)
     at rx.internal.operators.OperatorMerge$MergeSubscriber.emitScalar(OperatorMerge.java:395)
     at rx.internal.operators.OperatorMerge$MergeSubscriber.tryEmit(OperatorMerge.java:355)
     at rx.internal.operators.OperatorMerge$InnerSubscriber.onNext(OperatorMerge.java:846)
     at zlc.season.rxdownload.function.FileHelper.saveFile(FileHelper.java:142)
     at zlc.season.rxdownload.function.DownloadHelper.saveNormalFile(DownloadHelper.java:152)
     at zlc.season.rxdownload.entity.DownloadType$NormalDownload$1.call(DownloadType.java:48)
     at zlc.season.rxdownload.entity.DownloadType$NormalDownload$1.call(DownloadType.java:45)
     at rx.Observable.unsafeSubscribe(Observable.java:10142)
     at rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:248)
     at rx.internal.operators.OperatorMerge$MergeSubscriber.onNext(OperatorMerge.java:148)
     at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:77)
     at rx.internal.operators.OperatorSubscribeOn$1$1.onNext(OperatorSubscribeOn.java:53)
     at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:173)
     at rx.internal.operators.OperatorSubscribeOn$1$1$1.request(OperatorSubscribeOn.java:80)
     at rx.Subscriber.setProducer(Subscriber.java:211)
     at rx.internal.operators.OnSubscribeMap$MapSubscriber.setProducer(OnSubscribeMap.java:102)
     at rx.internal.operators.OperatorSubscribeOn$1$1.setProducer(OperatorSubscribeOn.java:76)
     at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
     at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
     at rx.Observable.unsafeSubscribe(Observable.java:10142)
     at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
     at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230)
     at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:269)
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
     at java.lang.Thread.run(Thread.java:818)

同一个文件存在的时候,重复下载出错

java.lang.RuntimeException: unknown error
at zlc.season.rxdownload.RxDownload$16.call(RxDownload.java:510)
at zlc.season.rxdownload.RxDownload$16.call(RxDownload.java:502)
at rx.internal.operators.OnSubscribeMap$MapSubscriber.onNext(OnSubscribeMap.java:69)
at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:173)
at rx.internal.producers.ProducerArbiter.setProducer(ProducerArbiter.java:126)
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1$1.setProducer(OperatorRetryWithPredicate.java:122)
at rx.internal.operators.OnSubscribeMap$MapSubscriber.setProducer(OnSubscribeMap.java:102)
at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
at rx.Observable.unsafeSubscribe(Observable.java:10151)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
at rx.Observable.unsafeSubscribe(Observable.java:10151)
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127)
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73)
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52)
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79)
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45)
at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276)
at rx.Subscriber.setProducer(Subscriber.java:209)
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138)
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.Observable.unsafeSubscribe(Observable.java:10151)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.Observable.unsafeSubscribe(Observable.java:10151)
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)
at rx.Observable.unsafeSubscribe(Observable.java:10151)
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41)
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.Observable.unsafeSubscribe(Observable.java:10151)
at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:228)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
Caused by: rx.excepti

image

断点下载问题

您好,大神,我想问下你这断点下载具体怎么实现的啊?我没怎么看懂,当暂停时,上次的下载进度大小在哪里记录的?然后传入到下次继续下载里

打正式包时候 运行崩溃 是不是混淆的问题

ava.lang.IllegalArgumentException: Missing either @Head URL or @url parameter.
for method a.b
retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:720)
retrofit2.ServiceMethod$Builder.methodError(ServiceMethod.java:711)
retrofit2.ServiceMethod$Builder.build(ServiceMethod.java:206)
retrofit2.Retrofit.loadServiceMethod(Retrofit.java:166)
retrofit2.Retrofit$1.invoke(Retrofit.java:145)
java.lang.reflect.Proxy.invoke(Proxy.java:397)
$Proxy1.b(Unknown Source)
zlc.season.rxdownload2.function.b.f(DownloadHelper.java:324)
zlc.season.rxdownload2.function.b.e(DownloadHelper.java:318)
zlc.season.rxdownload2.function.b.a(DownloadHelper.java:158)
zlc.season.rxdownload2.function.DownloadService$b.run(DownloadService.java:1306)
java.lang.Thread.run(Thread.java:818)

能否判断是否有文件正在下载?

需求是在退出应用的时候判断是否要继续下载,所以能否判断是否有文件正在下载?应该加上判断数据库正在下载的记录是不是大于0就好了吧?

关于DownloadService的运行控制

你好,我在使用该库的时候,发现 DownloadService 启动的 DownloadMissionDispatchRunnable 线程是无法在 RxDownload 中控制的,是否可以在 RxDownload 中增加一个控制 DownloadService 的方法(检查服务状态、开启、关闭)呢?

另外,还有一个小问题,RxIoScheduler-(.*) 这些下载线程里面,会出现最后一个线程的下载速度非常慢,通常一个50MB的文件,用浏览器下载是在10秒内,但是使用RxDownload下载需要30-40秒才完成。原因就是最后启动的一个 RxIoScheduler 线程速度非常慢。

关于使用Rxjava2与Rxjava1

使用Retorfit+Rxjava结合时,只能使用Retorfit2+Rxjava1,使用Rxjava2会包冲突,希望作者能继续维护使用Rxjava1跟官方同步。

快速暂停和继续下载队列异常

在设置同时只进行1个任务进行下时,快速乱序的点击多个任务的暂停和继续按钮,会出现下载队列异常,导致出现多个任务同时下载的情况。且部分任务出现无法暂停的情况。

下载失败时,提示Context is NULL! You should call #RxDownload.context(Context context)#

12-14 20:17:01.031 14896-15081/com.star.app.tvhelper.ui.shanxi W/RxDownload: java.lang.IllegalStateException: Context is NULL! You should call #RxDownload.context(Context context)# first!
at zlc.season.rxdownload.RxDownload$11.call(RxDownload.java:430)
at rx.internal.util.ActionObserver.onCompleted(ActionObserver.java:49)
at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onCompleted(OnSubscribeDoOnEach.java:63)
at rx.internal.operators.OperatorMerge$MergeSubscriber.emitLoop(OperatorMerge.java:656)
at rx.internal.operators.OperatorMerge$MergeSubscriber.emit(OperatorMerge.java:568)
at rx.internal.operators.OperatorMerge$MergeProducer.request(OperatorMerge.java:133)
at rx.internal.operators.OperatorSubscribeOn$1$1$1$1.call(OperatorSubscribeOn.java:85)
at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:228)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1115)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:590)
at java.lang.Thread.run(Thread.java:818)

多次调用下载方法,不抛异常,改为监听上次下载的状态

多次调用下载方法时,如果已存在该下载任务,则会直接抛异常。
=> 是否可以改为:已存在下载任务,则监听上次下载的状态。

比如这样的场景:

需要下载一个配置文件,可能在A位置或B位置 开始下载,AB位置需要同时显示下载状态。

如果所有类似场景都自己去判断,那代码必然变得很臃肿。

而且,如果在调用download() 之前没有去判断是否存在该任务,基本都是不太关心是否有存在相同任务的,只是希望把文件下载回来,调用download()后能监听到文件的下载情况。

Utils类的mkdirs函数里面是不是应该调用mkdirs呢

public static void mkdirs(String... paths) throws IOException {
    for (String each : paths) {
        File file = new File(each);
        if (file.exists() && file.isDirectory()) {
            log(DIR_EXISTS_HINT, each);
        } else {
            log(DIR_NOT_EXISTS_HINT, each);
            boolean flag = file.mkdir();   // 这里推荐使用mkdirs,防止父文件夹不存在的情况
            if (flag) {
                log(DIR_CREATE_SUCCESS, each);
            } else {
                log(DIR_CREATE_FAILED, each);
                throw new IOException(format(getDefault(), DIR_CREATE_FAILED, each));
            }
        }
    }
}

有时下载完了不回调onsuccess

我用下面这种代码在fragment中使用,有时下载完成了不回调onsuccess反而回调onerror这是什么原因啊

RxPermissions.getInstance(mContext)
		.request(WRITE_EXTERNAL_STORAGE)
		.doOnNext(new Consumer<Boolean>() })
		.observeOn(Schedulers.io())
		.compose(rxDownload.<Boolean>transform(...)
		.observeOn(AndroidSchedulers.mainThread())
		.subscribe(new Observer<DownloadStatus>() {
	@Override
	public void onSubscribe(Disposable d) {
		//
	}
	@Override
	public void onNext(DownloadStatus status) { }
	
	@Override
	public void onError(Throwable e) { }
		
	@Override
	public void onComplete() { }
});

如何在下载文件前获取文件是否下载过和下载是否完成的状态?还有能否加入同时查询多个url的状态和值?以及能否加入没有文件名称自动获取服务器的文件名?

使用getDownloadRecord方法如果没有下载过,数据库没有记录onnext方法不会调用。
public Observable readRecord(final String url) {
return Observable.create(new Observable.OnSubscribe() {
@OverRide
public void call(Subscriber<? super DownloadRecord> subscriber) {
Cursor cursor = null;
try {
cursor = getReadableDatabase().rawQuery("select * from " + TABLE_NAME +
" where " + "url=?", new String[]{url});
while (cursor.moveToNext()) {
subscriber.onNext(Db.RecordTable.read(cursor));
}
subscriber.onCompleted();
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
cursor.moveToNext()为false的时候没有onnext的调用只有onCompleted
获取不到文件的状态。

DownloadService 中的mWaitingForDownload数据结构有问题

private class DownloadMissionDispatchRunnable implements Runnable {

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                DownloadMission mission = mWaitingForDownload.peek();
                if (null != mission) {
                    ...
                }
            }
        }
    }

这里的mWaitingForDownload = new LinkedList<>()不是阻塞队列,while相当于一个死循环。
导致这个服务在后台跑时相当费电。
mWaitingForDownload应该是一个BlockingQueue才对的

下载完后等待1.5秒的方式待商阙

我看了一下代码, 这里两个地方:
一个是: 下载完后, 在流还未关完的情况下, 就进行了onComplete, 这样子有一些不妥当. 最好是在流关闭完后, 再进行onComplete;
一个是: 因为不是在流关闭后进行onComplete, 所以在doOnCompleted中, 等待1.5s再执行其它的事后操作. 这种方式有一些被动.

https支持

https下载300M左右的视频,暂停以后就无法继续下载了

后台下载的时候怎么加权限?

        mRxDownload.serviceDownload(url, saveName, savePath)
            .subscribe(new Action1<Object>() {

这种下载的时候怎么加权限
// RxPermissions.getInstance(this)
// .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
// .doOnNext(new Action1() {
// @OverRide
// public void call(Boolean granted) {
// if (!granted) {
// Toast.makeText(musicApplication, "ھوقۇقنى تەمىنلىمەپسىز", Toast.LENGTH_SHORT).show();
// throw new RuntimeException("no permission");
// }
// }
// })

这个功能怎么实现

Got Error on Huawei V8.

Code:

        disposable = RxDownload.getInstance(this)
                .maxThread(5)//5线程
                .maxRetryCount(3)//错误重试次数
                .download(currentUrl)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<DownloadStatus>() {
                    @Override
                    public void accept(@NonNull DownloadStatus status) throws Exception {
                        Logger.d("RxDownload信息...DownloadSize:" + status.getDownloadSize() + "...TotalSize" + status.getTotalSize() + "...Percent" + status.getPercentNumber());
                        pbDownload.setProgress((int) status.getPercentNumber());
                        tvNetSpeed.setText(status.getFormatDownloadSize() + "/" + status.getFormatTotalSize());
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(@NonNull Throwable throwable) throws Exception {
                        Logger.d("RxDownload信息...onError");
                        throwable.printStackTrace();
                    }
                }, new Action() {
                    @Override
                    public void run() throws Exception {
                        long time = System.currentTimeMillis() - startTime;
                        long resultTime = time / 1000;
                        Logger.d("RxDownload信息...onComplete:耗时" + resultTime);
                    }
                });

Exception:

03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Download/.cache/3c5d8fe0-4f1d-4f4e-b7c5-59f2c4b4e9fd.apk.lmf: open failed: ENOENT (No such file or directory)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:455)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at java.io.RandomAccessFile.<init>(RandomAccessFile.java:247)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.function.FileHelper.writeLastModify(FileHelper.java:295)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.function.FileHelper.prepareDownload(FileHelper.java:107)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.entity.TemporaryRecord.prepareRangeDownload(TemporaryRecord.java:113)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.entity.DownloadType$MultiThreadDownload.prepareDownload(DownloadType.java:297)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.function.DownloadHelper.download(DownloadHelper.java:134)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.function.DownloadHelper.access$200(DownloadHelper.java:43)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.function.DownloadHelper$3.apply(DownloadHelper.java:115)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at zlc.season.rxdownload2.function.DownloadHelper$3.apply(DownloadHelper.java:112)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onNext(ObservableFlatMap.java:121)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.tryEmit(ObservableFlatMap.java:262)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$InnerObserver.onNext(ObservableFlatMap.java:554)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drainLoop(ObservableFlatMap.java:434)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.drain(ObservableFlatMap.java:323)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$InnerObserver.onSubscribe(ObservableFlatMap.java:541)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarXMapObservable.subscribeActual(ObservableScalarXMap.java:163)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.subscribeInner(ObservableFlatMap.java:162)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onNext(ObservableFlatMap.java:139)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:103)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.tryEmit(ObservableFlatMap.java:262)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$InnerObserver.onNext(ObservableFlatMap.java:554)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableRetryBiPredicate$RetryBiObserver.onNext(ObservableRetryBiPredicate.java:66)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:64)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:103)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.CallObservable.subscribeActual(CallObservable.java:43)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableMap.subscribeActual(ObservableMap.java:33)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableRetryBiPredicate$RetryBiObserver.subscribeNext(ObservableRetryBiPredicate.java:100)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableRetryBiPredicate.subscribeActual(ObservableRetryBiPredicate.java:39)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.subscribeInner(ObservableFlatMap.java:162)
03-08 16:23:05.185 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onNext(ObservableFlatMap.java:139)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableRetryBiPredicate$RetryBiObserver.onNext(ObservableRetryBiPredicate.java:66)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableMap$MapObserver.onNext(ObservableMap.java:64)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach$DoOnEachObserver.onNext(ObservableDoOnEach.java:103)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at com.jakewharton.retrofit2.adapter.rxjava2.CallObservable.subscribeActual(CallObservable.java:43)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableMap.subscribeActual(ObservableMap.java:33)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableRetryBiPredicate$RetryBiObserver.subscribeNext(ObservableRetryBiPredicate.java:100)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableRetryBiPredicate.subscribeActual(ObservableRetryBiPredicate.java:39)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarXMapObservable.subscribeActual(ObservableScalarXMap.java:166)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap.subscribeActual(ObservableFlatMap.java:55)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap.subscribeActual(ObservableFlatMap.java:55)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.subscribeInner(ObservableFlatMap.java:162)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap$MergeObserver.onNext(ObservableFlatMap.java:139)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.observers.DisposableLambdaObserver.onNext(DisposableLambdaObserver.java:59)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableScalarXMap$ScalarDisposable.run(ObservableScalarXMap.java:248)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableJust.subscribeActual(ObservableJust.java:35)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnLifecycle.subscribeActual(ObservableDoOnLifecycle.java:33)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap.subscribeActual(ObservableFlatMap.java:55)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableFlatMap.subscribeActual(ObservableFlatMap.java:55)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.186 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableDoFinally.subscribeActual(ObservableDoFinally.java:45)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Observable.subscribe(Observable.java:10700)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run(ObservableSubscribeOn.java:39)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.Scheduler$1.run(Scheduler.java:138)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:59)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:51)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at java.lang.Thread.run(Thread.java:776)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at libcore.io.Posix.open(Native Method)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:187)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:441)
03-08 16:23:05.187 29448-29448/com.floatingmuseum.androidtest W/System.err: 	... 81 more

I found there no .cache dir in Download directory

按照教程的方法进行服务下载有个问题

03-23 14:46:27.435 17450-17528/com.example.sand.rxjava I/RxDownload: Mission coming!
03-23 14:46:27.451 17450-17528/com.example.sand.rxjava I/RxDownload: DownloadQueue waiting for mission come...
03-23 14:46:27.534 17450-17527/com.example.sand.rxjava V/RenderScript: Application requested CPU execution
03-23 14:46:27.539 17450-17527/com.example.sand.rxjava V/RenderScript: 0xaf75ee00 Launching thread(s), CPUs 4

点了下载后就这样,没有进度也没有开始下载,按照md中教程写的

数据库是自动存储的吗

那如果我下次需要得到已经下载和未完成的,是不是需要自己查询数据库呢?若sevice异常关闭,数据库会有问题不?

测试了一下demo发现了几个问题

  1. 应用下载暂停继续 会发现点击继续后 不会下载

  2. 是否可以设置最大下载数量,比如下载数量 为2,其他下载的显示为等待状态

  3. 更新进度条时 不是连续的,是跳跃似的更新,

下载卡顿

点击下载 界面特别卡请问库当中有哪个方法可以解决

下载进度会超过100%

我在测试过程中进行多线程多任务下载发现有些任务的下载进度会超过100%,请问一下是否是多线程导致的问题?

关于第三方依赖库

上传JCenter的时候,compile写成provided,
然后告诉使用者自己去添加哪些依赖库会灵活点。
当然你现在用的参数配置的法子也不是不行,只是个人建议~:smile:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.