Kii BLOG

以断点续传的方式上传下载文件(2)

(一)概述

上一篇文章我们讨论了以断点续传的方式上传文件,与之对应的就是文件的下载,其代码的相关处理也是和上传文件基本对应的,下面的链接是示例源码:

DownloadingFiles

 

(二)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”状态,其执行效果如下图所示:

UploadingFiles

 

4、手动暂停下载任务

点击处于”downloading”状态的任务,会提示是否暂停该任务,选中”yes”则暂停任务。

5、恢复下载任务

那些被暂停了的或者由于某种原因(例如网络断开)而产生错误的任务,可以通过点击列表的相应item恢复下载。

6、终止和删除任务

长按列表中处于下载任务类的相应item项,可以手动终止那些正在下载或出错的任务,或者清除那些已经完成的任务。

7、下载那些尚未完成上传任务的文件

如果试图下载那些尚未完成上传的文件会怎样呢,答案是下载过程中会提示错误,错误类型为”NotFoundException”。

(八)总结

从以上分析可以看出,Kii Cloud为文件下载提供了简洁和实用的接口,开发者可以很容易的管理下载任务,完全不必关心断点续传的内部机制,只需要调用几个接口就轻松地完成文件的下载和管理。

 

 相关文章:

以断点续传的方式上传下载文件(1)

以断点续传的方式上传下载文件(2)

发表评论