本文主要介绍在OPhone中如何实现文件的下载、暂停、恢复、重试以及清除。我们仅仅使用ContentResolver的insert、query、update、delete就可以完成上述功能。对于上层的开发者来说,下载的启动、进行、完成、出错仅仅体现在数据库中对应下载记录的这一行数据的变化。下面我们分别看一下。
1、 下载
在
OPhone中要下载一个文件,实际上就是添加一条记录到数据库表中。这就需要提供被添加的表名以及这条记录的数据,如下:
view plain copy to clipboard print ?
- Uri contentUri = getContentResolver().insert(
- Uri.parse("content://downloads/download"), values);
这里,
Uri.parse("content://downloads/download")就是对应的数据库表,它实际的位置在
什么地方呢,让我们看看:
..
view plain copy to clipboard print ?
- .# adb shell
-
- # cd /data/data/com.android.providers.downloads/databases
-
- # ls
-
- downloads.db
-
- # sqlite3 downloads.db
-
- SQLite version 3.5.9
-
- Enter ".help" for instructions
-
- sqlite> .tables
-
- android_metadata downloads
-
- sqlite>
如上黑体字,
downloads这个表对外的接口就是这个uri,稍后我们会在不同的状态时看看表里数据有什么变化。
我们继续看第二个参数,
values是一个ContentValues对象,这里面存放着我们本次下载的信息也就是downloads表中该行的输入数据。
view plain copy to clipboard print ?
- ContentValues values = new ContentValues();
- values.put(Downloads.COLUMN_TITLE, filename);
- values.put(Downloads.COLUMN_URI, url);
- values.put(Downloads.COLUMN_FILE_NAME_HINT, filename);
- values.put(Downloads.COLUMN_NOTIFICATION_PACKAGE, getPackageName());
- values.put(Downloads.COLUMN_NOTIFICATION_CLASS,
- TestDownload.DownloadReceiver.class.getName());
- values.put(Downloads.COLUMN_VISIBILITY,
- Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
- values.put(Downloads.COLUMN_DESCRIPTION, Uri.parse(url).getHost());
- values.put(Downloads.COLUMN_STOREPATH, Constant.STORE_DOWNLOAD);
顾名思义,
Downloads.COLUMN_URI即为该文件的url,它完全可以像这样:
http://192.168.2.50/share/Dell/Mini_3v/configuration.zip,还有一项比较重要的数据是
Downloads.COLUMN_STOREPATH,这是下载存储路径,不设置的话默认是/sdcard/download。
另外
insert方法返回的是一个Uri,它就是这条记录的主键键值。
当我们执行完
insert后,我们会发现downloads表中多出一条数据:
view plain copy to clipboard print ?
- sqlite> .mode line
-
- sqlite> select * from downloads;
-
- _id = 1
-
- uri = http:
-
- ...
-
- control = 0
-
- status = 192
-
- numfailed = 0
-
- lastmod = 946685297415
-
- ...
- storepath = /data/dm/
-
- port =
-
这里需要留意一下粗体字的两列
control与status,后面我们会讲到。
2、 暂停/恢复/重试
我们通过更新这条记录的
control列来控制下载的状态。
1)暂停:
view plain copy to clipboard print ?
- ContentValues values = new ContentValues();
- values.put(Downloads.COLUMN_CONTROL, Downloads.CONTROL_PAUSE_BY_USER);
- getContentResolver().update(contentUri, values, null, null);
这里
contentUri就是刚才insert返回的Uri。values存放的是要更改的信息。我们仅仅把control这一列的值修改为Downloads.
CONTROL_PAUSE_BY_USER即为
10,就能暂停本次下载,执行上面的语句再查看一下数据库:
view plain copy to clipboard print ?
- sqlite> select * from downloads;
-
- _id = 1
-
- uri = http:
-
- ...
-
- control = 10
-
- status = 194
-
- ...
- description = 192.168.2.50
-
- scanned =
-
- interface =
-
- proxy =
-
- storepath = /data/dm/
-
- port =
状态已经自动改为
194。
2)恢复:
view plain copy to clipboard print ?
- ContentValues values = new ContentValues();
- values.put(Downloads.COLUMN_CONTROL, Downloads.CONTROL_RUN);
- getContentResolver().update(contentUri, values, null, null);
是不是非常简单,我们把
control这一列的值修改为Downloads.
CONTROL_RUN,就可以继续本次下载,而这条下载记录变化为:
view plain copy to clipboard print ?
- sqlite> select control,status from downloads;
-
- control = 0
-
- status = 192
-
- sqlite>
control与
status已经恢复为insert时的值。
3)重试:
在一些情况下,下载会失败,这时的数据库状态是什么呢?
view plain copy to clipboard print ?
- sqlite> select control,status from downloads;
-
- control = 0
-
- status = 490
-
- sqlite>
与恢复时比较不难理解,
control的方式在下载失败时并没有改变,只不过状态变化了。看看如何重试:
view plain copy to clipboard print ?
- ContentValues values = new ContentValues();
- values.put(Downloads.COLUMN_CONTROL, Downloads.CONTROL_RUN);
- values.put(Downloads.COLUMN_STATUS, Downloads.STATUS_RETRY);
- getContentResolver().update(contentUri, values, null, null);
这与暂停后恢复的处理有一点点区别,我们除了把
control修改为Downloads.
CONTROL_RUN,还需要把
status置成Downloads.
STATUS_RETRY。执行该代码,继续查看数据库:
view plain copy to clipboard print ?
- sqlite> select control,status from downloads;
-
- control = 0
-
- status = 192
-
- sqlite>
又变成下载进行中的状态的了。
3、 清除
下载的过程中我们希望取消本次操作,怎么办?也很简单:
view plain copy to clipboard print ?
- getContentResolver().delete(contentUri, null, null);
请注意,取消操作仅仅是把这条下载记录从表中删除,而不会删除已经下载的文件。查看这个表:
view plain copy to clipboard print ?
- sqlite> select count(*) from downloads;
-
- count(*) = 0
-
- sqlite>
下载目录中的数据没有被删除:
view plain copy to clipboard print ?
- # pwd
-
- /data/dm
-
- # ls
-
- degrade.zip
-
- #
4、 监听
如果想在下载的不同状态时做一些处理,就需要注册一个ContentObserver来监听下载的状态。
view plain copy to clipboard print ?
- DownloadObserver observer = new DownloadObserver();
- getContentResolver().registerContentObserver(contentUri, true, observer);
- 仍然,contentUri是我们下载对应的这条记录,而DownloadObserver继承于ContentObserver,我们用它覆盖ContentObserver的onChange方法,加上自己的逻辑,比如下载完成后弹出一个对话框通知用户等等。
- private class DownloadObserver extends ContentObserver {
- public DownloadObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean flag) {
-
- }
- }
5、 其他一些下载方法
除了利用上述
DownloadManager下载文件外,还有一些其他的方法同样能完成下载功能。
比如利用
java.net.URL与java.net.URLConnection:
view plain copy to clipboard print ?
- URL url = new URL(xmlURL);
- URLConnection con = url.openConnection();
- InputStream in = con.getInputStream();
- ...
还可以利用
org.apache.http包的一些类:
view plain copy to clipboard print ?
- DefaultHttpClient httpclient = new DefaultHttpClient();
- HttpGet req = new HttpGet(url);
- HttpResponse response = httpclient.execute(req);
- HttpEntity resEntity = response.getEntity();
- InputStream is = resEntity.getContent();
- ...
由于篇幅关系,这里就不一一介绍了。文后将附上利用
DownloadManager下载的代码与AndroidManifest.xml。
附录:
view plain copy to clipboard print ?
- TestDownload.java
-
- package com.OPhone.test;
-
- import android.app.Activity;
- import android.content.ContentUris;
- import android.content.ContentValues;
- import android.database.ContentObserver;
- import android.database.Cursor;
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Handler;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.TextView;
-
- public class TestDownload extends Activity {
-
- private final String URL = "http://192.168.2.172/share/test/apologize.mp3";
- private Cursor mDownloadCursor;
- private Uri contentUri;
- private Button btn_start;
- private Button btn_pause;
- private Button btn_resume;
- private Button btn_cancel;
- private Button btn_retry;
- private TextView txt_process;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- txt_process = (TextView) findViewById(R.id.txt_process);
- btn_start = (Button) findViewById(R.id.btn_start);
- btn_pause = (Button) findViewById(R.id.btn_pause);
- btn_resume = (Button) findViewById(R.id.btn_resume);
- btn_cancel = (Button) findViewById(R.id.btn_cancel);
- btn_retry = (Button) findViewById(R.id.btn_retry);
-
- btn_start.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- start();
- }
- });
- btn_pause.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- pause();
- }
- });
- btn_resume.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- resume();
- }
- });
- btn_cancel.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- cancel();
- }
- });
- btn_retry.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- retry();
- }
- });
- }
-
- private void start() {
- ContentValues values = new ContentValues();
- values.put("title", "apologize.mp3");
- values.put("uri", URL);
- values.put("notificationpackage", getPackageName());
- values.put("notificationclass", TestDownload.class.getName());
- values.put("visibility", 1);
- values.put("description", Uri.parse(URL).getHost());
- values.put("storepath", "/sdcard/download/");
- contentUri = getContentResolver().insert(
- Uri.parse("content://downloads/download"), values);
- mDownloadCursor = query();
- DownloadObserver observer = new DownloadObserver();
- getContentResolver()
- .registerContentObserver(contentUri, true, observer);
- };
-
- private void resume() {
- ContentValues values = new ContentValues();
- values.put("control", 0);
- getContentResolver().update(contentUri, values, null, null);
- };
-
- private void pause() {
- ContentValues values = new ContentValues();
- values.put("control", 10);
- getContentResolver().update(contentUri, values, null, null);
- };
-
- private void cancel() {
- getContentResolver().delete(contentUri, null, null);
- };
-
- private void retry() {
- ContentValues values = new ContentValues();
- values.put("control", 10);
- values.put("status", 195);
- getContentResolver().update(contentUri, values, null, null);
- };
-
- private Cursor query() {
- String selection = "_id = '" + ContentUris.parseId(contentUri) + "'";
- return managedQuery(Uri.parse("content://downloads/download"),
- new String[] { "total_bytes", "current_bytes" }, selection,
- null, null);
- }
-
- private int point = 0;
-
- private class DownloadObserver extends ContentObserver {
- public DownloadObserver() {
- super(new Handler());
- }
-
- @Override
- public void onChange(boolean flag) {
- if (mDownloadCursor.getCount() <= 0) {
- return;
- }
- String points = "";
- point = (point + 1) % 7;
- for (int i = 0; i < point; i++) {
- points += ".";
- }
- txt_process.setText(points);
- }
- }
- }
-
- AndroidManifest.xml
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.OPhone.test"
- android:versionCode="1"
- android:versionName="1.0">
-
- <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
-
- <application android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:name=".TestDownload"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
-
- </application>
-
- </manifest>
效果
作者:
黄鹏——播思通讯
(声明:本网的新闻及文章版权均属OPhone SDN网站所有,如需转载请与我们编辑团队联系。任何媒体、网站或个人未经本网书面协议授权,不得进行任何形式的转载。已经取得本网协议授权的媒体、网站,在转载使用时请注明稿件来源。)