下载

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

1、 下载
OPhone中要下载一个文件,实际上就是添加一条记录到数据库表中。这就需要提供被添加的表名以及这条记录的数据,如下:
  1. UricontentUri=getContentResolver().insert(
  2. Uri.parse("content://downloads/download"),values);
这里, Uri.parse("content://downloads/download")就是对应的数据库表,它实际的位置在
什么地方呢,让我们看看:
..
  1. .#adbshell
  2. #cd/data/data/com.android.providers.downloads/databases
  3. #ls
  4. downloads.db
  5. #sqlite3downloads.db
  6. SQLiteversion3.5.9
  7. Enter".help"forinstructions
  8. sqlite>.tables
  9. android_metadatadownloads
  10. sqlite>
如上黑体字, downloads这个表对外的接口就是这个uri,稍后我们会在不同的状态时看看表里数据有什么变化。
我们继续看第二个参数, values是一个ContentValues对象,这里面存放着我们本次下载的信息也就是downloads表中该行的输入数据。
  1. ContentValuesvalues=newContentValues();
  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);
另外 insert方法返回的是一个Uri,它就是这条记录的主键键值。
当我们执行完 insert后,我们会发现downloads表中多出一条数据:
  1. sqlite>.modeline
  2. sqlite>select*fromdownloads;
  3. _id=1
  4. uri=http://192.168.2.50/share/degrade.zip
  5. ...
  6. control=0
  7. status=192
  8. numfailed=0
  9. lastmod=946685297415
  10. ...
  11. storepath=/data/dm/
  12. port=
这里需要留意一下粗体字的两列 control与status,后面我们会讲到。
2、 暂停/恢复/重试
我们通过更新这条记录的 control列来控制下载的状态。
1)暂停:
  1. ContentValuesvalues=newContentValues();
  2. values.put(Downloads.COLUMN_CONTROL,Downloads.CONTROL_PAUSE_BY_USER);
  3. getContentResolver().update(contentUri,values,null,null);
这里 contentUri就是刚才insert返回的Uri。values存放的是要更改的信息。我们仅仅把control这一列的值修改为Downloads. CONTROL_PAUSE_BY_USER即为 10,就能暂停本次下载,执行上面的语句再查看一下数据库:
  1. sqlite>select*fromdownloads;
  2. _id=1
  3. uri=http://192.168.2.50/share/degrade.zip
  4. ...
  5. control=10
  6. status=194
  7. ...
  8. description=192.168.2.50
  9. scanned=
  10. interface=
  11. proxy=
  12. storepath=/data/dm/
  13. port=
状态已经自动改为 194。
2)恢复:
  1. ContentValuesvalues=newContentValues();
  2. values.put(Downloads.COLUMN_CONTROL,Downloads.CONTROL_RUN);
  3. getContentResolver().update(contentUri,null);
是不是非常简单,我们把 control这一列的值修改为Downloads. CONTROL_RUN,就可以继续本次下载,而这条下载记录变化为:
  1. sqlite>selectcontrol,statusfromdownloads;
  2. control=0
  3. status=192
  4. sqlite>
controlstatus已经恢复为insert时的值。
3)重试:
在一些情况下,下载会失败,这时的数据库状态是什么呢?
  1. sqlite>selectcontrol,statusfromdownloads;
  2. control=0
  3. status=490
  4. sqlite>
与恢复时比较不难理解, control的方式在下载失败时并没有改变,只不过状态变化了。看看如何重试:
  1. ContentValuesvalues=newContentValues();
  2. values.put(Downloads.COLUMN_CONTROL,Downloads.CONTROL_RUN);
  3. values.put(Downloads.COLUMN_STATUS,Downloads.STATUS_RETRY);
  4. getContentResolver().update(contentUri,null);
这与暂停后恢复的处理有一点点区别,我们除了把 control修改为Downloads. CONTROL_RUN,还需要把 status置成Downloads. STATUS_RETRY。执行该代码,继续查看数据库:
  1. sqlite>selectcontrol,statusfromdownloads;
  2. control=0
  3. status=192
  4. sqlite>
又变成下载进行中的状态的了。
3、 清除
下载的过程中我们希望取消本次操作,怎么办?也很简单:
  1. getContentResolver().delete(contentUri,null,null);
请注意,取消操作仅仅是把这条下载记录从表中删除,而不会删除已经下载的文件。查看这个表:
  1. sqlite>selectcount(*)fromdownloads;
  2. count(*)=0
  3. sqlite>
下载目录中的数据没有被删除:
  1. #pwd
  2. /data/dm
  3. #ls
  4. degrade.zip
  5. #
4、 监听
如果想在下载的不同状态时做一些处理,就需要注册一个ContentObserver来监听下载的状态。
  1. DownloadObserverobserver=newDownloadObserver();
  2. getContentResolver().registerContentObserver(contentUri,true,observer);
  3. 仍然,contentUri是我们下载对应的这条记录,而DownloadObserver继承于ContentObserver,我们用它覆盖ContentObserver的onChange方法,加上自己的逻辑,比如下载完成后弹出一个对话框通知用户等等。
  4. privateclassDownloadObserverextendsContentObserver{
  5. publicDownloadObserver(){
  6. super(newHandler());
  7. }
  8. @Override
  9. publicvoidonChange(booleanflag){
  10. //dosomething
  11. }
  12. }
5、 其他一些下载方法
除了利用上述 DownloadManager下载文件外,还有一些其他的方法同样能完成下载功能。
比如利用 java.net.URL与java.net.URLConnection:
  1. URLurl=newURL(xmlURL);
  2. URLConnectioncon=url.openConnection();
  3. InputStreamin=con.getInputStream();
  4. ...
还可以利用 org.apache.http包的一些类:
  1. DefaultHttpClienthttpclient=newDefaultHttpClient();
  2. HttpGetreq=newHttpGet(url);
  3. HttpResponseresponse=httpclient.execute(req);
  4. HttpEntityresEntity=response.getEntity();
  5. InputStreamis=resEntity.getContent();
  6. ...
由于篇幅关系,这里就不一一介绍了。文后将附上利用 DownloadManager下载的代码与AndroidManifest.xml。
附录:
  1. TestDownload.java
  2. packagecom.OPhone.test;
  3. importandroid.app.Activity;
  4. importandroid.content.ContentUris;
  5. importandroid.content.ContentValues;
  6. importandroid.database.ContentObserver;
  7. importandroid.database.Cursor;
  8. importandroid.net.Uri;
  9. importandroid.os.Bundle;
  10. importandroid.os.Handler;
  11. importandroid.view.View;
  12. importandroid.view.View.OnClickListener;
  13. importandroid.widget.Button;
  14. importandroid.widget.TextView;
  15. publicclassTestDownloadextendsActivity{
  16. privatefinalStringURL="http://192.168.2.172/share/test/apologize.mp3";
  17. privateCursormDownloadCursor;
  18. privateUricontentUri;
  19. privateButtonbtn_start;
  20. privateButtonbtn_pause;
  21. privateButtonbtn_resume;
  22. privateButtonbtn_cancel;
  23. privateButtonbtn_retry;
  24. privateTextViewtxt_process;
  25. @Override
  26. publicvoidonCreate(BundlesavedInstanceState){
  27. super.onCreate(savedInstanceState);
  28. setContentView(R.layout.main);
  29. txt_process=(TextView)findViewById(R.id.txt_process);
  30. btn_start=(Button)findViewById(R.id.btn_start);
  31. btn_pause=(Button)findViewById(R.id.btn_pause);
  32. btn_resume=(Button)findViewById(R.id.btn_resume);
  33. btn_cancel=(Button)findViewById(R.id.btn_cancel);
  34. btn_retry=(Button)findViewById(R.id.btn_retry);
  35. btn_start.setOnClickListener(newOnClickListener(){
  36. publicvoidonClick(Viewv){
  37. start();
  38. }
  39. });
  40. btn_pause.setOnClickListener(newOnClickListener(){
  41. publicvoidonClick(Viewv){
  42. pause();
  43. }
  44. });
  45. btn_resume.setOnClickListener(newOnClickListener(){
  46. publicvoidonClick(Viewv){
  47. resume();
  48. }
  49. });
  50. btn_cancel.setOnClickListener(newOnClickListener(){
  51. publicvoidonClick(Viewv){
  52. cancel();
  53. }
  54. });
  55. btn_retry.setOnClickListener(newOnClickListener(){
  56. publicvoidonClick(Viewv){
  57. retry();
  58. }
  59. });
  60. }
  61. privatevoidstart(){
  62. ContentValuesvalues=newContentValues();
  63. values.put("title","apologize.mp3");
  64. values.put("uri",URL);
  65. values.put("notificationpackage",getPackageName());
  66. values.put("notificationclass",TestDownload.class.getName());
  67. values.put("visibility",1);
  68. values.put("description",Uri.parse(URL).getHost());
  69. values.put("storepath","/sdcard/download/");
  70. contentUri=getContentResolver().insert(
  71. Uri.parse("content://downloads/download"),values);
  72. mDownloadCursor=query();
  73. DownloadObserverobserver=newDownloadObserver();
  74. getContentResolver()
  75. .registerContentObserver(contentUri,observer);
  76. };
  77. privatevoidresume(){
  78. ContentValuesvalues=newContentValues();
  79. values.put("control",0);
  80. getContentResolver().update(contentUri,null);
  81. };
  82. privatevoidpause(){
  83. ContentValuesvalues=newContentValues();
  84. values.put("control",10);
  85. getContentResolver().update(contentUri,null);
  86. };
  87. privatevoidcancel(){
  88. getContentResolver().delete(contentUri,null);
  89. };
  90. privatevoidretry(){
  91. ContentValuesvalues=newContentValues();
  92. values.put("control",10);
  93. values.put("status",195);
  94. getContentResolver().update(contentUri,null);
  95. };
  96. privateCursorquery(){
  97. Stringselection="_id='"+ContentUris.parseId(contentUri)+"'";
  98. returnmanagedQuery(Uri.parse("content://downloads/download"),
  99. newString[]{"total_bytes","current_bytes"},selection,
  100. null,null);
  101. }
  102. privateintpoint=0;
  103. privateclassDownloadObserverextendsContentObserver{
  104. publicDownloadObserver(){
  105. super(newHandler());
  106. }
  107. @Override
  108. publicvoidonChange(booleanflag){
  109. if(mDownloadCursor.getCount()<=0){
  110. return;
  111. }
  112. Stringpoints="";
  113. point=(point+1)%7;
  114. for(inti=0;i<point;i++){
  115. points+=".";
  116. }
  117. txt_process.setText(points);
  118. }
  119. }
  120. }
  121. AndroidManifest.xml
  122. <?xmlversion="1.0"encoding="utf-8"?>
  123. <manifestxmlns:android="http://schemas.android.com/apk/res/android"
  124. package="com.OPhone.test"
  125. android:versionCode="1"
  126. android:versionName="1.0">
  127. <uses-permissionandroid:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
  128. <applicationandroid:icon="@drawable/icon"android:label="@string/app_name">
  129. <activityandroid:name=".TestDownload"
  130. android:label="@string/app_name">
  131. <intent-filter>
  132. <actionandroid:name="android.intent.action.MAIN"/>
  133. <categoryandroid:name="android.intent.category.LAUNCHER"/>
  134. </intent-filter>
  135. </activity>
  136. </application>
  137. </manifest>
效果

作者:

黄鹏——播思通讯

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


SQLite架构简单,又有Json计算能力,有时会承担Json文件/RESTful的计算功能,但SQLite不能直接解析Json文件/RESTful,需要用Java代码硬写,或借助第三方类库,最后再拼成insert语句插入数据表,代码非常繁琐,这里就不展示了。参考前面的代码可知,入库的过程比较麻烦,不能只用SQL,还要借助Java或命令行。SPL是现代的数据计算语言,属于简化的面向对象的语言风格,有对象的概念,可以用点号访问属性并进行多步骤计算,但没有继承重载这些内容,不算彻底的面向对象语言。...
使用Python操作内置数据库SQLite以及MySQL数据库。
破解微信数据库密码,用python导出微信聊天记录
(Unity)SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。本教程将告诉您如何使用 SQLite 编程,并让你迅速上手。.................................
安卓开发,利用SQLite实现登陆注册功能
相比大多数数据库而言,具有等优势,广泛应用于、等领域。
有时候,一个项目只有一个数据库,比如只有SQLite,或者MySQL数据库,那么我们只需要使用一个固定的数据库即可。但是一个项目如果写好了,有多个用户使用,但是多个用户使用不同的数据库,这个时候,我们就需要把软件设计成可以连接多个数据库的模式,用什么数据库,就配置什么数据库即可。4.Users实体类,这个实体类要和数据库一样的,形成一一对应的关系。11.Sqlite数据库,需要在代码里面创建数据库,建立表,再建立数据。8.我们开启MySQL数据库,然后进行调试,看程序的结果。2.安装SqlSugar。
基于Android的背单词软件,功能强大完整。
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统。说白了就是使用起来轻便简单,
Android的简单购物车案例
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库...
Qt设计较为美观好看的登录注册界面(包含SQLite数据库以及TCP通信的应用)
SQLite是用C语言开发的跨平台小型数据库,可嵌入其他开发语言,也可在单机执行。SPL是用Java开发的跨平台的数据计算语言,可嵌入Java,可在单机执行,可以数据计算服务的形式被远程调用。两者的代码都是解释执行的。...
新建库.openDATA_BASE;新建表createtableLIST_NAME(DATA);语法:NAME关键字...<用逗号分割>删除表droptableNAME;查看表.schema查看表信息新建数据insertintoLIST_NAMEvalues();语法:CLASS,PARAMETER...,CLASS是类别,PARAMETER是参数<用逗号分割新建的
importsqlite3classDemo01:def__init__(self):self.conn=sqlite3.connect("sql_demo_001.db")self.cursor1=self.conn.cursor()self.cursor1.execute("select*fromtable_001wherename=?andid=?",('ssss&#0
 在客户端配置文件<configuration>节点下,添加:<connectionStrings>      <add name="localdb" connectionString="Data Source=config/local.db;Version=3;UseUTF16Encoding=True;" providerName="System.Data.SQLite.SQLiteFactory"/&g
提到锁就不得不说到死锁的问题,而SQLite也可能出现死锁。下面举个例子:连接1:BEGIN(UNLOCKED)连接1:SELECT...(SHARED)连接1:INSERT...(RESERVED)连接2:BEGIN(UNLOCKED)连接2:SELECT...(SHARED)连接1:COMMIT(PENDING,尝试获取EXCLUSIVE锁,但还有SHARED锁未释放,返回SQLITE_BUSY)连接2:INSERT...
SQLite是一种嵌入式数据库,它的数据库就是一个文件。由于SQLite本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在iOS和Android的App中都可以集成。Python就内置了SQLite3,所以,在Python中使用SQLite,不需要安装任何东西,直接使用。在使用SQLite前,我们先要搞清楚几个概念:表
设计思想————首先要确定有几个页面、和每个页面的大致布局由于是入门,我也是学习了不是很长的时间,所以项目比较low。。。。第一个页面,也就是打开APP的首页面:今天这个博客,先实现添加功能!:首先对主界面进行布局:其中activity_main.xml的代码为<?xmlversion="1.0"encoding="