SODownloader icon indicating copy to clipboard operation
SODownloader copied to clipboard

记录下载中任务的resumeData

Open zzqlplq opened this issue 5 years ago • 6 comments

AFNetworking有通知,可以在应用被杀死时获取下载任务的resumeData,原来的applicationWillTerminate没有用。第一次pull,如果操作不当,还请指正。

zzqlplq avatar Aug 31 '18 07:08 zzqlplq

你好,感谢你的提交,我下载了你的resumeSave分支,在我的手机上运行了Demo,当我正执行一个下载任务时强制退出App,下次启动App后,下载进度还是从0%的地方开始的。你再试试?

scfhao avatar Aug 31 '18 09:08 scfhao

额,我这边试过,AFNetworking的通知的确能获取到resumeData,不过如果退出过快,有时候的确没办法获取,但是大部分情况下都能正常获取到,你可以多试几次看看

zzqlplq avatar Aug 31 '18 14:08 zzqlplq

还是回归代码吧,你的思路是通过注册 AFNetworking 中的AFNetworkingTaskDidCompleteNotification 通知,我们看一下这个通知的发送时机,如下(AFURLSessionManager.m):

dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{
            if (self.completionHandler) {
                self.completionHandler(task.response, responseObject, error);
            }

            dispatch_async(dispatch_get_main_queue(), ^{
                [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
            });
        });

上面的代码中可以看到 AFNetworking 在发送此通知前,会先调用completionHandle,也就是说如果这个通知能做到的事completionHandle也可以做到,而我们的代码先前已实现completionHandle,所以通过AFNetworkingTaskDidCompleteNotification 的思路并不是最佳的。

另外,你提交的代码会对所有下载失败的情况保存resumeData,包含取消下载的情况,这显然也是不合理的。

scfhao avatar Sep 02 '18 03:09 scfhao

哦哦,不好意思,是我疏忽了,我发现你的确做了处理,但是很奇怪,我运行你的代码,杀掉后每次还是从0开始下载,但是用AFNetworking的通知,却能获取到杀掉进程前的进度。重新理一下逻辑,打了断点,发现应该是因为你的completionHandle创建的太晚的原因, URLSession:task:didCompleteWithError: 方法在你创建和之前相同identifier的session时,就已经开始调用了,但是你的completionHandle却是在开始下载的时候才创建,我打了断点,在 URLSession:task:didCompleteWithError: 方法里,completionHandler是空的,block没有调用,我添加的通知是在你初始化的时候添加,所以能获取到。

zzqlplq avatar Sep 02 '18 06:09 zzqlplq

对了,还发现一点,下载中杀到进程,error给的错误也是NSURLErrorCancelled,但是因为没有调用cancelByProducingResumeData:,所以调用你的handelError: forItem: 方法,还是没有办法存储resumeData

zzqlplq avatar Sep 02 '18 07:09 zzqlplq

更新一下我现在对这个功能的一些想法与大家探讨:

  1. 该方案是在 AFNetworking 结束下载通知保存的下载进度,而之所以会有这个通知是因为在 applicationWillTerminate 通知方法中执行了cancelByProducingResumeData 方法,虽然这个地方的保存进度没生效,却导致了下载结束通知的发送。(只要把 applicationWillTerminate 通知方法注释掉,下载结束的通知也就收不到了)

也就是说在收到 applicationWillTerminate 通知后,cancelByProducingResumeData 方法确实执行了,只是取消方法中的异步block参数(保存进度)没有执行,但是 AFNetworking 的 failBlock 会执行,而之前的代码在 failBlock 中对 cancel 的情况忽略了,所以更好的方案是在这个 failBlock 中对由于 App关闭导致的下载取消情况进行保存进度。

  1. 该方案会保存所有取消情况下的下载进度,这是不合理的。如果是用户操作的取消下载,不应该保存。

今年有些忙,所以一直没回复,以上是我的观点,不一定是正确的,欢迎继续探讨。

为方便交流 SODownloader 开发问题,我刚才建一个QQ群(858515629),欢迎加入。

scfhao avatar Oct 09 '18 03:10 scfhao