下载

来源:互联网 发布:mac os 原版dmg镜像 编辑:程序博客网 时间:2024/04/25 22:30

本文主要介绍在OPhone中如何实现文件的下载、暂停、恢复、重试以及清除。我们仅仅使用ContentResolver的insert、query、update、delete就可以完成上述功能。对于上层的开发者来说,下载的启动、进行、完成、出错仅仅体现在数据库中对应下载记录的这一行数据的变化。下面我们分别看一下。

 1、 下载
OPhone中要下载一个文件,实际上就是添加一条记录到数据库表中。这就需要提供被添加的表名以及这条记录的数据,如下:
        
view plaincopy to clipboardprint?
  1. Uri contentUri = getContentResolver().insert(  
  2.                 Uri.parse("content://downloads/download"), values);  
 
 这里,Uri.parse("content://downloads/download")就是对应的数据库表,它实际的位置在
什么地方呢,让我们看看:
..
view plaincopy to clipboardprint?
  1. .# adb shell  
  2.    
  3. # cd /data/data/com.android.providers.downloads/databases  
  4.    
  5. # ls  
  6.    
  7. downloads.db  
  8.    
  9. # sqlite3 downloads.db  
  10.    
  11. SQLite version 3.5.9  
  12.    
  13. Enter ".help" for instructions  
  14.    
  15. sqlite> .tables  
  16.    
  17. android_metadata downloads         
  18.    
  19. sqlite>   
 
    如上黑体字,downloads这个表对外的接口就是这个uri,稍后我们会在不同的状态时看看表里数据有什么变化。
    我们继续看第二个参数,values是一个ContentValues对象,这里面存放着我们本次下载的信息也就是downloads表中该行的输入数据。
view plaincopy to clipboardprint?
  1. ContentValues values = new ContentValues();  
  2.   values.put(Downloads.COLUMN_TITLE, filename);  
  3.   values.put(Downloads.COLUMN_URI, url);  
  4.   values.put(Downloads.COLUMN_FILE_NAME_HINT, filename);  
  5.   values.put(Downloads.COLUMN_NOTIFICATION_PACKAGE, getPackageName());  
  6.   values.put(Downloads.COLUMN_NOTIFICATION_CLASS,  
  7.           TestDownload.DownloadReceiver.class.getName());  
  8.   values.put(Downloads.COLUMN_VISIBILITY,  
  9.           Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);  
  10.   values.put(Downloads.COLUMN_DESCRIPTION, Uri.parse(url).getHost());  
  11.   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 plaincopy to clipboardprint?
  1. sqlite> .mode line  
  2.    
  3. sqlite> select * from downloads;  
  4.    
  5.                 _id = 1  
  6.    
  7.                 uri = http://192.168.2.50/share/degrade.zip  
  8.    
  9.                ...  
  10.    
  11.             control = 0  
  12.    
  13.              status = 192  
  14.    
  15.           numfailed = 0  
  16.    
  17.             lastmod = 946685297415  
  18.    
  19.                ...  
  20.           storepath = /data/dm/  
  21.    
  22.                port =   
  23.    
 
    这里需要留意一下粗体字的两列control与status,后面我们会讲到。
 
2、 暂停/恢复/重试
    我们通过更新这条记录的control列来控制下载的状态。
    1)暂停:
    
view plaincopy to clipboardprint?
  1. ContentValues values = new ContentValues();  
  2.     values.put(Downloads.COLUMN_CONTROL, Downloads.CONTROL_PAUSE_BY_USER);  
  3.     getContentResolver().update(contentUri, values, nullnull);  
    这里contentUri就是刚才insert返回的Uri。values存放的是要更改的信息。我们仅仅把control这一列的值修改为Downloads.CONTROL_PAUSE_BY_USER即为10,就能暂停本次下载,执行上面的语句再查看一下数据库:
view plaincopy to clipboardprint?
  1. sqlite> select * from downloads;  
  2.    
  3.                 _id = 1  
  4.    
  5.                 uri = http://192.168.2.50/share/degrade.zip  
  6.    
  7.                ...  
  8.    
  9.             control = 10  
  10.    
  11.              status = 194  
  12.    
  13.                ...  
  14.         description = 192.168.2.50  
  15.    
  16.             scanned =   
  17.    
  18.           interface =   
  19.    
  20.               proxy =   
  21.    
  22.           storepath = /data/dm/  
  23.    
  24.                port =   
 
    状态已经自动改为194。
    2)恢复:
  
view plaincopy to clipboardprint?
  1. ContentValues values = new ContentValues();  
  2.   values.put(Downloads.COLUMN_CONTROL, Downloads.CONTROL_RUN);  
  3.   getContentResolver().update(contentUri, values, nullnull);  
是不是非常简单,我们把control这一列的值修改为Downloads.CONTROL_RUN,就可以继续本次下载,而这条下载记录变化为:
view plaincopy to clipboardprint?
  1. sqlite> select control,status from downloads;  
  2.    
  3. control = 0  
  4.    
  5.  status = 192  
  6.    
  7. sqlite>   
 
    controlstatus已经恢复为insert时的值。
  
  3)重试:
    在一些情况下,下载会失败,这时的数据库状态是什么呢?
view plaincopy to clipboardprint?
  1. sqlite> select control,status from downloads;  
  2.    
  3. control = 0  
  4.    
  5.  status = 490  
  6.    
  7. sqlite>   
 
    与恢复时比较不难理解,control的方式在下载失败时并没有改变,只不过状态变化了。看看如何重试:
  
view plaincopy to clipboardprint?
  1. ContentValues values = new ContentValues();  
  2.   values.put(Downloads.COLUMN_CONTROL, Downloads.CONTROL_RUN);  
  3.   values.put(Downloads.COLUMN_STATUS, Downloads.STATUS_RETRY);  
  4.   getContentResolver().update(contentUri, values, nullnull);  
 
    这与暂停后恢复的处理有一点点区别,我们除了把control修改为Downloads.CONTROL_RUN,还需要把status置成Downloads.STATUS_RETRY。执行该代码,继续查看数据库:
view plaincopy to clipboardprint?
  1. sqlite> select control,status from downloads;  
  2.    
  3. control = 0  
  4.    
  5.  status = 192  
  6.    
  7. sqlite>   
 
    又变成下载进行中的状态的了。
 
3、 清除
    下载的过程中我们希望取消本次操作,怎么办?也很简单:
           
view plaincopy to clipboardprint?
  1. getContentResolver().delete(contentUri, nullnull);  
    请注意,取消操作仅仅是把这条下载记录从表中删除,而不会删除已经下载的文件。查看这个表:
view plaincopy to clipboardprint?
  1. sqlite> select count(*) from downloads;  
  2.    
  3. count(*) = 0  
  4.    
  5. sqlite>   
 
    下载目录中的数据没有被删除:
view plaincopy to clipboardprint?
  1. # pwd  
  2.    
  3. /data/dm  
  4.    
  5. # ls  
  6.    
  7. degrade.zip  
  8.    
  9. #   
 
   
4、 监听
    如果想在下载的不同状态时做一些处理,就需要注册一个ContentObserver来监听下载的状态。
view plaincopy to clipboardprint?
  1. DownloadObserver observer = new DownloadObserver();  
  2. getContentResolver().registerContentObserver(contentUri, true, observer);  
  3.     仍然,contentUri是我们下载对应的这条记录,而DownloadObserver继承于ContentObserver,我们用它覆盖ContentObserver的onChange方法,加上自己的逻辑,比如下载完成后弹出一个对话框通知用户等等。  
  4.     private class DownloadObserver extends ContentObserver {  
  5.         public DownloadObserver() {  
  6.             super(new Handler());  
  7.         }  
  8.    
  9.         @Override  
  10.         public void onChange(boolean flag) {  
  11.             // do something  
  12.         }  
  13.     }  
   
 
5、 其他一些下载方法
    除了利用上述DownloadManager下载文件外,还有一些其他的方法同样能完成下载功能。
    比如利用java.net.URL与java.net.URLConnection:
view plaincopy to clipboardprint?
  1. URL url = new URL(xmlURL);  
  2. URLConnection con = url.openConnection();  
  3. InputStream in = con.getInputStream();  
  4. ...  
 
    还可以利用org.apache.http包的一些类:
  
view plaincopy to clipboardprint?
  1. DefaultHttpClient httpclient = new DefaultHttpClient();  
  2.   HttpGet req = new HttpGet(url);  
  3.   HttpResponse response = httpclient.execute(req);  
  4.   HttpEntity resEntity = response.getEntity();  
  5.   InputStream is = resEntity.getContent();  
  6.   ...  
 
    由于篇幅关系,这里就不一一介绍了。文后将附上利用DownloadManager下载的代码与AndroidManifest.xml。
 
附录:
view plaincopy to clipboardprint?
  1. TestDownload.java  
  2.    
  3. package com.OPhone.test;  
  4.    
  5. import android.app.Activity;  
  6. import android.content.ContentUris;  
  7. import android.content.ContentValues;  
  8. import android.database.ContentObserver;  
  9. import android.database.Cursor;  
  10. import android.net.Uri;  
  11. import android.os.Bundle;  
  12. import android.os.Handler;  
  13. import android.view.View;  
  14. import android.view.View.OnClickListener;  
  15. import android.widget.Button;  
  16. import android.widget.TextView;  
  17.    
  18. public class TestDownload extends Activity {  
  19.    
  20.     private final String URL = "http://192.168.2.172/share/test/apologize.mp3";  
  21.     private Cursor mDownloadCursor;  
  22.     private Uri contentUri;  
  23.     private Button btn_start;  
  24.     private Button btn_pause;  
  25.     private Button btn_resume;  
  26.     private Button btn_cancel;  
  27.     private Button btn_retry;  
  28.     private TextView txt_process;  
  29.    
  30.     @Override  
  31.     public void onCreate(Bundle savedInstanceState) {  
  32.         super.onCreate(savedInstanceState);  
  33.         setContentView(R.layout.main);  
  34.         txt_process = (TextView) findViewById(R.id.txt_process);  
  35.         btn_start = (Button) findViewById(R.id.btn_start);  
  36.         btn_pause = (Button) findViewById(R.id.btn_pause);  
  37.         btn_resume = (Button) findViewById(R.id.btn_resume);  
  38.         btn_cancel = (Button) findViewById(R.id.btn_cancel);  
  39.         btn_retry = (Button) findViewById(R.id.btn_retry);  
  40.    
  41.         btn_start.setOnClickListener(new OnClickListener() {  
  42.             public void onClick(View v) {  
  43.                 start();  
  44.             }  
  45.         });  
  46.         btn_pause.setOnClickListener(new OnClickListener() {  
  47.             public void onClick(View v) {  
  48.                 pause();  
  49.             }  
  50.         });  
  51.         btn_resume.setOnClickListener(new OnClickListener() {  
  52.             public void onClick(View v) {  
  53.                 resume();  
  54.             }  
  55.         });  
  56.         btn_cancel.setOnClickListener(new OnClickListener() {  
  57.             public void onClick(View v) {  
  58.                 cancel();  
  59.             }  
  60.         });  
  61.         btn_retry.setOnClickListener(new OnClickListener() {  
  62.             public void onClick(View v) {  
  63.                 retry();  
  64.             }  
  65.         });  
  66.     }  
  67.    
  68.     private void start() {  
  69.         ContentValues values = new ContentValues();  
  70.         values.put("title""apologize.mp3");  
  71.         values.put("uri", URL);  
  72.         values.put("notificationpackage", getPackageName());  
  73.         values.put("notificationclass", TestDownload.class.getName());  
  74.         values.put("visibility"1);  
  75.         values.put("description", Uri.parse(URL).getHost());  
  76.         values.put("storepath""/sdcard/download/");  
  77.         contentUri = getContentResolver().insert(  
  78.                 Uri.parse("content://downloads/download"), values);  
  79.         mDownloadCursor = query();  
  80.         DownloadObserver observer = new DownloadObserver();  
  81.         getContentResolver()  
  82.                 .registerContentObserver(contentUri, true, observer);  
  83.     };  
  84.    
  85.     private void resume() {  
  86.         ContentValues values = new ContentValues();  
  87.         values.put("control"0);  
  88.         getContentResolver().update(contentUri, values, nullnull);  
  89.     };  
  90.    
  91.     private void pause() {  
  92.         ContentValues values = new ContentValues();  
  93.         values.put("control"10);  
  94.         getContentResolver().update(contentUri, values, nullnull);  
  95.     };  
  96.    
  97.     private void cancel() {  
  98.         getContentResolver().delete(contentUri, nullnull);  
  99.     };  
  100.    
  101.     private void retry() {  
  102.         ContentValues values = new ContentValues();  
  103.         values.put("control"10);  
  104.         values.put("status"195);  
  105.         getContentResolver().update(contentUri, values, nullnull);  
  106.     };  
  107.    
  108.     private Cursor query() {  
  109.         String selection = "_id = '" + ContentUris.parseId(contentUri) + "'";  
  110.         return managedQuery(Uri.parse("content://downloads/download"),  
  111.                 new String[] { "total_bytes""current_bytes" }, selection,  
  112.                 nullnull);  
  113.     }  
  114.    
  115.     private int point = 0;  
  116.    
  117.     private class DownloadObserver extends ContentObserver {  
  118.         public DownloadObserver() {  
  119.             super(new Handler());  
  120.         }  
  121.    
  122.         @Override  
  123.         public void onChange(boolean flag) {  
  124.             if (mDownloadCursor.getCount() <= 0) {  
  125.                 return;  
  126.             }  
  127.             String points = "";  
  128.             point = (point + 1) % 7;  
  129.             for (int i = 0; i < point; i++) {  
  130.                 points += ".";  
  131.             }  
  132.             txt_process.setText(points);  
  133.         }  
  134.     }  
  135. }  
  136.    
  137. AndroidManifest.xml  
  138. <?xml version="1.0" encoding="utf-8"?>  
  139. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  140.       package="com.OPhone.test"  
  141.       android:versionCode="1"  
  142.       android:versionName="1.0">  
  143.    
  144.     <uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>  
  145.    
  146.     <application android:icon="@drawable/icon" android:label="@string/app_name">  
  147.         <activity android:name=".TestDownload"  
  148.                   android:label="@string/app_name">  
  149.             <intent-filter>  
  150.                 <action android:name="android.intent.action.MAIN" />  
  151.                 <category android:name="android.intent.category.LAUNCHER" />  
  152.             </intent-filter>  
  153.         </activity>  
  154.    
  155.     </application>  
  156.    
  157. </manifest>   
 
 
效果

 

作者:

黄鹏——播思通讯

(声明:本网的新闻及文章版权均属OPhone SDN网站所有,如需转载请与我们编辑团队联系。任何媒体、网站或个人未经本网书面协议授权,不得进行任何形式的转载。已经取得本网协议授权的媒体、网站,在转载使用时请注明稿件来源。)

原创粉丝点击