Kii BLOG
以断点续传的方式上传下载文件(2)
(一)概述
上一篇文章我们讨论了以断点续传的方式上传文件,与之对应的就是文件的下载,其代码的相关处理也是和上传文件基本对应的,下面的链接是示例源码:
(二)KiiFileBucket下的KiiFile列表
在文件下载之前,首先需要列出基于KiiFileBucket下的所有KiiFile,在代码实现上需要完成以下几个步骤:
- 创建一个KiiQuery实例并按照创建时间排序
- 调用KiiFileBucket的query方法
- 调用KiiQueryResult的getResult获取到KiiFile列表
其相关代码如下:
KiiQuery query = new KiiQuery(null); query.sortByAsc("_created"); KiiFileBucket fbucket = KiiUser.getCurrentUser().fileBucket(BUCKET_NAME); fbucket.query(new KiiQueryCallBack<KiiFile>() { public void onQueryCompleted(int token, KiiQueryResult<KiiFile> result, java.lang.Exception e) { if (e == null) { // add the KiiFiles to the adapter (adding to the listview) List<KiiFile> kiiFilesLists = result.getResult(); for (KiiFile kiiFile : kiiFilesLists) { ... ... } } else { ... ... } } }, query, false);
(三)用断点续传的方式下载文件
1. 获取Title
首先获取kiiFile实例下的Title,并以该Title命名本地存储的文件,这里需要注意的一点是在通过getTitle方法获取文件名的时候可能返回值为null,这是因为在文件上传时,如果创建KiiFile实例时没有使用本地File作为参数初始化,则该KiiFile的Title将不予初始化,例如下面的第一条语句是带有本地File参数的KiiFile创建方法,而第二条则是不带File参数的KiiFile创建方法:
kfile = Kii.fileBucket(BUCKET_NAME).file(localFile); kfile = Kii.fileBucket(BUCKET_NAME).file();
详细的代码可以参考上一篇文章“以断点续传的方式上传文件”中提到的示例代码。
2. 创建KiiDownloader实例
创建KiiDownloader实例的相关代码如下:
final DownloaderObj o = MainActivity.this.mListAdapter.getItem(position); DownloaderObj mDownloaderObj = null; KiiDownloader mDownloader = null; String title; if (o.kiiFile.getTitle() != null) { title = o.kiiFile.getTitle().toString(); } else { title = "default"; } try { mDownloader = o.kiiFile.downloader(getApplicationContext(), new File(Environment.getExternalStorageDirectory(), title)); } catch (Exception e) { Toast.makeText(MainActivity.this, "Error adding downloaders: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); return; } mDownloaderObj = new DownloaderObj(); mDownloaderObj.downloader = mDownloader; mDownloaderObj.status = STATUS_DOWNLOADING; mListAdapter.add(mDownloaderObj); new DownloadFileTask().execute(mDownloaderObj);
其中如果KiiFile的Title为空的情况下,使用“default”作为本地存储的文件名,在创建完KiiDownloader实例之后,通过任务DownloadFileTask下载文件。
3. 文件下载
在执行下载方法之前,需要调用调用KiiFile实例的refresh
方法获取文件的元数据,可以通过KiiDownloader示例的getFileHolder方法获取到KiiFile实例,然后调用KiiFile的refresh方法,相关代码如下:
try { mKiiFile = (KiiFile)(mDownloaderObj.downloader.getFileHolder()); mKiiFile.refresh(); } catch (Exception e) { if (e != null) { ... ... } }
在刷新完KiiFile之后,通过transferAsync函数实现文件的断点续传方式的下载,并通过回调函数完成下载进度和下载完成的提示,相关代码如下:
mDownloaderObj.downloader.transferAsync( new KiiRTransferCallback() { public void onStart(KiiRTransfer operator) { mDownloaderObj.status = STATUS_DOWNLOADING; mListAdapter.notifyDataSetChanged(); } public void onProgress(KiiRTransfer operator, long completedInBytes, long totalSizeinBytes) { mDownloaderObj.completedInBytes = completedInBytes; mDownloaderObj.totalSizeinBytes = totalSizeinBytes; mListAdapter.notifyDataSetChanged(); } public void onTransferCompleted(KiiRTransfer operator, java.lang.Exception e) { if (e == null) { mDownloaderObj.status = STATUS_FINISHED; mListAdapter.notifyDataSetChanged(); } else { mDownloaderObj.status = STATUS_ERROR; mListAdapter.notifyDataSetChanged(); Toast.makeText(MainActivity.this, "Error downloading KiiFiles: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); } } });
(四)恢复暂停的下载任务
恢复暂停的下载任务在示例app里分为两种情况,一种是程序启动时恢复所有基于该用户指定fileBucket下处于挂起状态的任务,另外一种就是app执行过程中由用户手动暂停的任务,二者最终调用都是上面提到的transferAsync方法,下面分这两种情况分别说明:
1、app启动时的下载任务恢复
启动时的下载任务恢复主要完成以下几步工作:
- 获取当前用户下指定的KiiFileBucket实例
- 通过KiiFileBucket获取KiiRTransferManager实例
- 通过KiiRTransferManager的listDownloadEntries获取处于挂起状态的KiiDownloader实例列表
下面是具体的示例代码:
boolean isError = false; DownloaderObj mDownloaderObj = null; mProgress = ProgressDialog.show(MainActivity.this, "", "Loading downloaders...", true); KiiFileBucket fbucket = KiiUser.getCurrentUser().fileBucket(BUCKET_NAME); KiiRTransferManager manager = fbucket.getTransferManager(); List<KiiDownloader> suspended = null; try { suspended = manager.listDownloadEntries(getApplicationContext()); } catch (StateStoreAccessException e1){ // Failed to access the local storage. // This is a rare error; you should be able to safely retry. Toast.makeText(MainActivity.this, "Error loading downloaders: " + e1.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); isError = true; } if (isError == false) { for (KiiDownloader downloader : suspended) { mDownloaderObj = new DownloaderObj(); mDownloaderObj.downloader = downloader; mDownloaderObj.status = STATUS_DOWNLOADING; mListAdapter.add(mDownloaderObj); new DownloadFileTask().execute(mDownloaderObj); } } mProgress.dismiss();
从上面的代码中可以看出,在获取到KiiDownloader实例之后,还是通过任务DownloadFileTask完成后台文件的下载。
2、恢复手动暂停的任务
在示例代码中,如果下载任务处于暂停或错误状态,此时点击该列表item,会提示是否恢复任务,在这种情况下直接通过后台任务重新下载该KiiDownloader即可,示例代码如下:
void performResume(int position) { final DownloaderObj o = MainActivity.this.mListAdapter.getItem(position); new DownloadFileTask().execute(o); }
(五)手动暂停文件下载
如果一个下载任务正在执行,可以通过手动暂停的方式暂停该任务,本示例代码中采用suspendAsync方法暂停任务,并通过回调函数onSuspendCompleted判断暂停返回的结果,示例代码如下:
void performSuspend(int position) { // show a progress dialog to the user mProgress = ProgressDialog.show(MainActivity.this, "", "Suspending object...", true); // get the object to delete based on the index of the row that was tapped final DownloaderObj o = MainActivity.this.mListAdapter.getItem(position); // delete the object asynchronously o.downloader.suspendAsync( new KiiRTransferCallback() { public void onSuspendCompleted(KiiRTransfer operator, java.lang.Exception e) { if (e == null) { o.status = STATUS_SUSPENDED; } else { Toast.makeText(MainActivity.this, "Error suspending downloader: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); o.status = STATUS_ERROR; } mProgress.dismiss(); mListAdapter.notifyDataSetChanged(); } }); }
(六)手动终止文件下载
可以手动终止那些正在下载、已经挂起或处于错误状态的下载任务。下载任务一旦终止,则不能续传,只能重头开始下载,相关示例代码如下:
void performDelete(int position) { // show a progress dialog to the user mProgress = ProgressDialog.show(MainActivity.this, "", "Deleting downloader...", true); // get the object to delete based on the index of the row that was tapped final DownloaderObj o = MainActivity.this.mListAdapter.getItem(position); if (o.status == STATUS_FINISHED) { // remove the object from the list adapter MainActivity.this.mListAdapter.remove(o); mProgress.dismiss(); } else { // delete the object asynchronously o.downloader.terminateAsync( new KiiRTransferCallback() { public void onTerminateCompleted(KiiRTransfer operator, java.lang.Exception e) { if (e == null) { //Toast.makeText(MainActivity.this, "Deleted downloader", Toast.LENGTH_SHORT).show(); // remove the object from the list adapter MainActivity.this.mListAdapter.remove(o); } else { Toast.makeText(MainActivity.this, "Error deleting downloader: " + e.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); MainActivity.this.mListAdapter.remove(o); } mProgress.dismiss(); } }); } }
(七)示例app的测试方法
1、准备工作
在测试文件下载之前,需要保证Cloud端存在需要下载的文件,所以需要使用“以断点续传的方式上传文件”中提到的示例app上传几个文件。
2、登录和注册
首先通过用户管理界面完成登录或注册。
3、下载文件
进入任务管理界面之后,会看到任务列表总体分为两类,一类是Cloud端所有KiiFile文件,点击这些文件对应的item,会提示是否加入下载队列,另一类就是处于下载任务的item,其状态包括”downloading”,”suspended”,”finished”,”error”状态,其执行效果如下图所示:
4、手动暂停下载任务
点击处于”downloading”状态的任务,会提示是否暂停该任务,选中”yes”则暂停任务。
5、恢复下载任务
那些被暂停了的或者由于某种原因(例如网络断开)而产生错误的任务,可以通过点击列表的相应item恢复下载。
6、终止和删除任务
长按列表中处于下载任务类的相应item项,可以手动终止那些正在下载或出错的任务,或者清除那些已经完成的任务。
7、下载那些尚未完成上传任务的文件
如果试图下载那些尚未完成上传的文件会怎样呢,答案是下载过程中会提示错误,错误类型为”NotFoundException”。
(八)总结
从以上分析可以看出,Kii Cloud为文件下载提供了简洁和实用的接口,开发者可以很容易的管理下载任务,完全不必关心断点续传的内部机制,只需要调用几个接口就轻松地完成文件的下载和管理。
相关文章:
以断点续传的方式上传下载文件(2)