Android app基于DownloadProvider实现下载管理功能

下载功能是一个很常见的功能,在很多app中都有这种功能的存在。很多应用的做法是:写一个单线程或者多线程下载,写一个DownloadThread建立HTTP请求用来下载存储文件,存储到一个地方,然后写一个UI界面,用于展示文件列表。如果需求多了呢?加个控制,暂停、取消、重新下载、文件分类,再加上一些其他所谓的特定需求,加上数据库的操作管理会让你头大,况且下载功能,在很多细节方面还是需要处理很多的情况的(顺便说下,想看下载方面的深入研究,请看我的其他几篇博客)。

如果有一种方法,不用你写DownloadThread,不用你写HTTP请求,不用你写数据库,不用你自己操作控制,只需要你写一个界面,还能保证展示的内容是对的,BUG少,开发成本低,你会不会选择?

答案就是使用DownloadProvider来实现自己的下载管理功能。

大家可能对于DownloadProvider来说,都比较熟悉,app通过DownloadManager来进行下载文件,那么实际进行下载和管理文件的就是DownloadProvider,他的目录在packages/providers/DownloadProvider文件夹下面,那么我们怎么用这个DownloadProvider呢?

首先,在DownloadProvider里面有两个URI,一个是"content://downloads/my_downloads/"一个是"content://downloads/all_downloads/",其中"content://downloads/all_downloads/"是获取手机里面全部的下载资源数据,由于安全问题,这个是需要添加系统权限的,而一般app无法添加这种权限。而对于"content://downloads/my_downloads/",表示获取的是通过app本身进行下载的文件数据,这个无需系统权限,也就是说,通过这个uri可以获取到数据库(app本身下载的)内容,并进行增删改查以及下载控制。我们获取到了Cursor内容后,就可以把下载到的内容展示到界面上了,第一步完成。downloads.db中的字段很全,基本满足你想要的全部要求。

这里面有两点需要注意的:展示URI的数据,要同时满足两个条件:1.仅仅使用本app包名进行下载的,2.uid与DownloadProvider中存储的数据一致.这个我说明一下,当下载管理中建立一条数据的时候,会将这个时候发送给DownloadManager的app的uid记下来,删除app并重新安装,会导致app的uid发生变化,无法显示出之前下载过的数据,但覆盖安装不会收到影响

第二,下载管理。DownloadManager中的pauseDownload,restartDownload,resumeDownload等方法其实都是@hide的,不过我们可以通过复制这个方法来达到功能的实现,也无需反射。你所操作的数据,其实是DownloadProvider中的数据,举个例子,如果你删除一条数据,那么你去下载管理中再想找到这个条目,也是不可能的。

第三,注意事项。关于删除下载任务和下载文件的问题,先看下面的方法:

public static void removeData(Context context, long... ids) {
        DownloadManager manager = getDownloadManager(context);
        manager.remove(ids);
    }

这个方法很明显是通过id来删除下载的任务,删除之后,已经下载的文件也会被DownloadProvider给删除掉了,如果我只想删除数据库中的一条数据,而不想删除文件怎么办?开始的时候,尝试通过ContentResolver来删除,后来发现也是不可以的,DownloadProvider依然会删除文件。后来仔细分析数据库,发现有一个字段可以隐藏已经下载到的条目,看不见但是文件还存在。

public void removeDownload(long... ids){
        ContentValues values = new ContentValues();
        values.put("is_visible_in_downloads_ui", 0);
        if (ids.length == 1) {
            mContext.getContentResolver().update(ContentUris.withAppendedId(myDownloads, ids[0]), values,
                    null, null);
        }else{
            mContext.getContentResolver().update(myDownloads, values, getWhereClauseForIds(ids),
                    getWhereArgsForIds(ids));
        }
    }

static String getWhereClauseForIds(long[] ids) {
        StringBuilder whereClause = new StringBuilder();
        whereClause.append("(");
        for (int i = 0; i < ids.length; i++) {
            if (i > 0) {
                whereClause.append("OR ");
            }
            whereClause.append("_id");
            whereClause.append(" = ? ");
        }
        whereClause.append(")");
        return whereClause.toString();
    }

static String[] getWhereArgsForIds(long[] ids) {
        String[] whereArgs = new String[ids.length];
        for (int i = 0; i < ids.length; i++) {
            whereArgs[i] = Long.toString(ids[i]);
        }
        return whereArgs;
    }

你可能感兴趣的:(Android开发)