`
yidongkaifa
  • 浏览: 4064715 次
文章分类
社区版块
存档分类
最新评论

Android 断点续传

 
阅读更多
  1. packagecom.example.downloaderstopsart;
  2. importjava.util.ArrayList;
  3. importjava.util.HashMap;
  4. importjava.util.List;
  5. importjava.util.Map;
  6. importandroid.os.Bundle;
  7. importandroid.os.Handler;
  8. importandroid.os.Message;
  9. importandroid.os.StrictMode;
  10. importandroid.app.ListActivity;
  11. importandroid.view.View;
  12. importandroid.widget.LinearLayout;
  13. importandroid.widget.LinearLayout.LayoutParams;
  14. importandroid.widget.ProgressBar;
  15. importandroid.widget.SimpleAdapter;
  16. importandroid.widget.TextView;
  17. importandroid.widget.Toast;
  18. publicclassMainActivityextendsListActivity{
  19. //固定下载的资源路径,这里可以设置网络上的地址
  20. privatestaticfinalStringURL="http://10.81.36.193:8080/";
  21. //固定存放下载的音乐的路径:SD卡目录下
  22. privatestaticfinalStringSD_PATH="/mnt/sdcard/";
  23. //存放各个下载器
  24. privateMap<String,Downloader>downloaders=newHashMap<String,Downloader>();
  25. //存放与下载器对应的进度条
  26. privateMap<String,ProgressBar>ProgressBars=newHashMap<String,ProgressBar>();
  27. /**
  28. *利用消息处理机制适时更新进度条
  29. */
  30. privateHandlermHandler=newHandler(){
  31. publicvoidhandleMessage(Messagemsg){
  32. if(msg.what==1){
  33. Stringurl=(String)msg.obj;
  34. intlength=msg.arg1;
  35. ProgressBarbar=ProgressBars.get(url);
  36. if(bar!=null){
  37. //设置进度条按读取的length长度更新
  38. bar.incrementProgressBy(length);
  39. if(bar.getProgress()==bar.getMax()){
  40. Toast.makeText(MainActivity.this,"下载完成!",0).show();
  41. //下载完成后清除进度条并将map中的数据清空
  42. LinearLayoutlayout=(LinearLayout)bar.getParent();
  43. layout.removeView(bar);
  44. ProgressBars.remove(url);
  45. downloaders.get(url).delete(url);
  46. downloaders.get(url).reset();
  47. downloaders.remove(url);
  48. }
  49. }
  50. }
  51. }
  52. };
  53. @Override
  54. publicvoidonCreate(BundlesavedInstanceState){
  55. super.onCreate(savedInstanceState);
  56. setContentView(R.layout.activity_main);
  57. showListView();
  58. StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
  59. StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
  60. }
  61. //显示listView,这里可以随便添加音乐
  62. privatevoidshowListView(){
  63. List<Map<String,String>>data=newArrayList<Map<String,String>>();
  64. Map<String,String>map=newHashMap<String,String>();
  65. map.put("name","mm.mp3");
  66. data.add(map);
  67. map=newHashMap<String,String>();
  68. map.put("name","pp.mp3");
  69. data.add(map);
  70. map=newHashMap<String,String>();
  71. map.put("name","tt.mp3");
  72. data.add(map);
  73. map=newHashMap<String,String>();
  74. map.put("name","ou.mp3");
  75. data.add(map);
  76. SimpleAdapteradapter=newSimpleAdapter(this,data,R.layout.list_item,newString[]{"name"},
  77. newint[]{R.id.tv_resouce_name});
  78. setListAdapter(adapter);
  79. }
  80. /**
  81. *响应开始下载按钮的点击事件
  82. */
  83. publicvoidstartDownload(Viewv){
  84. //得到textView的内容
  85. LinearLayoutlayout=(LinearLayout)v.getParent();
  86. StringmusicName=((TextView)layout.findViewById(R.id.tv_resouce_name)).getText().toString();
  87. Stringurlstr=URL+musicName;
  88. Stringlocalfile=SD_PATH+musicName;
  89. //设置下载线程数为4,这里是我为了方便随便固定的
  90. intthreadcount=4;
  91. //初始化一个downloader下载器
  92. Downloaderdownloader=downloaders.get(urlstr);
  93. if(downloader==null){
  94. downloader=newDownloader(urlstr,localfile,threadcount,this,mHandler);
  95. downloaders.put(urlstr,downloader);
  96. }
  97. if(downloader.isdownloading())
  98. return;
  99. //得到下载信息类的个数组成集合
  100. LoadInfoloadInfo=downloader.getDownloaderInfors();
  101. //显示进度条
  102. showProgress(loadInfo,urlstr,v);
  103. //调用方法开始下载
  104. downloader.download();
  105. }
  106. /**
  107. *显示进度条
  108. */
  109. privatevoidshowProgress(LoadInfoloadInfo,Stringurl,Viewv){
  110. ProgressBarbar=ProgressBars.get(url);
  111. if(bar==null){
  112. bar=newProgressBar(this,null,android.R.attr.progressBarStyleHorizontal);
  113. bar.setMax(loadInfo.getFileSize());
  114. bar.setProgress(loadInfo.getComplete());
  115. ProgressBars.put(url,bar);
  116. LinearLayout.LayoutParamsparams=newLayoutParams(LayoutParams.FILL_PARENT,5);
  117. ((LinearLayout)((LinearLayout)v.getParent()).getParent()).addView(bar,params);
  118. }
  119. }
  120. /**
  121. *响应暂停下载按钮的点击事件
  122. */
  123. publicvoidpauseDownload(Viewv){
  124. LinearLayoutlayout=(LinearLayout)v.getParent();
  125. StringmusicName=((TextView)layout.findViewById(R.id.tv_resouce_name)).getText().toString();
  126. Stringurlstr=URL+musicName;
  127. downloaders.get(urlstr).pause();
  128. }
  129. }

DBHelper:

  1. packagecom.example.downloaderstopsart;
  2. importandroid.content.Context;
  3. importandroid.database.sqlite.SQLiteDatabase;
  4. importandroid.database.sqlite.SQLiteOpenHelper;
  5. /**
  6. *建立一个数据库帮助类
  7. */
  8. publicclassDBHelperextendsSQLiteOpenHelper{
  9. //download.db-->数据库名
  10. publicDBHelper(Contextcontext){
  11. super(context,"download.db",null,1);
  12. }
  13. /**
  14. *在download.db数据库下创建一个download_info表存储下载信息
  15. */
  16. @Override
  17. publicvoidonCreate(SQLiteDatabasedb){
  18. db.execSQL("createtabledownload_info(_idintegerPRIMARYKEYAUTOINCREMENT,thread_idinteger,"
  19. +"start_posinteger,end_posinteger,compelete_sizeinteger,urlchar)");
  20. }
  21. @Override
  22. publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
  23. }
  24. }

  1. DownloadInfo:
  1. packagecom.example.downloaderstopsart;
  2. publicclassDownloadInfo{
  3. privateintthreadId;//下载器id
  4. privateintstartPos;//开始点
  5. privateintendPos;//结束点
  6. privateintcompeleteSize;//完成度
  7. privateStringurl;//下载器网络标识
  8. publicDownloadInfo(intthreadId,intstartPos,intendPos,
  9. intcompeleteSize,Stringurl){
  10. this.threadId=threadId;
  11. this.startPos=startPos;
  12. this.endPos=endPos;
  13. this.compeleteSize=compeleteSize;
  14. this.url=url;
  15. }
  16. publicDownloadInfo(){
  17. }
  18. publicStringgetUrl(){
  19. returnurl;
  20. }
  21. publicvoidsetUrl(Stringurl){
  22. this.url=url;
  23. }
  24. publicintgetThreadId(){
  25. returnthreadId;
  26. }
  27. publicvoidsetThreadId(intthreadId){
  28. this.threadId=threadId;
  29. }
  30. publicintgetStartPos(){
  31. returnstartPos;
  32. }
  33. publicvoidsetStartPos(intstartPos){
  34. this.startPos=startPos;
  35. }
  36. publicintgetEndPos(){
  37. returnendPos;
  38. }
  39. publicvoidsetEndPos(intendPos){
  40. this.endPos=endPos;
  41. }
  42. publicintgetCompeleteSize(){
  43. returncompeleteSize;
  44. }
  45. publicvoidsetCompeleteSize(intcompeleteSize){
  46. this.compeleteSize=compeleteSize;
  47. }
  48. @Override
  49. publicStringtoString(){
  50. return"DownloadInfo[threadId="+threadId+",startPos="+startPos
  51. +",endPos="+endPos+",compeleteSize="+compeleteSize
  52. +"]";
  53. }
  54. }

LoadInfo:

  1. packagecom.example.downloaderstopsart;
  2. publicclassLoadInfo{
  3. publicintfileSize;//文件大小
  4. privateintcomplete;//完成度
  5. privateStringurlstring;//下载器标识
  6. publicLoadInfo(intfileSize,intcomplete,Stringurlstring){
  7. this.fileSize=fileSize;
  8. this.complete=complete;
  9. this.urlstring=urlstring;
  10. }
  11. publicLoadInfo(){
  12. }
  13. publicintgetFileSize(){
  14. returnfileSize;
  15. }
  16. publicvoidsetFileSize(intfileSize){
  17. this.fileSize=fileSize;
  18. }
  19. publicintgetComplete(){
  20. returncomplete;
  21. }
  22. publicvoidsetComplete(intcomplete){
  23. this.complete=complete;
  24. }
  25. publicStringgetUrlstring(){
  26. returnurlstring;
  27. }
  28. publicvoidsetUrlstring(Stringurlstring){
  29. this.urlstring=urlstring;
  30. }
  31. @Override
  32. publicStringtoString(){
  33. return"LoadInfo[fileSize="+fileSize+",complete="+complete
  34. +",urlstring="+urlstring+"]";
  35. }
  36. }

Downloader:

  1. packagecom.example.downloaderstopsart;
  2. importjava.io.File;
  3. importjava.io.InputStream;
  4. importjava.io.RandomAccessFile;
  5. importjava.net.HttpURLConnection;
  6. importjava.net.URL;
  7. importjava.util.ArrayList;
  8. importjava.util.List;
  9. importandroid.content.Context;
  10. importandroid.os.Handler;
  11. importandroid.os.Message;
  12. importandroid.util.Log;
  13. publicclassDownloader{
  14. privateStringurlstr;//下载的地址
  15. privateStringlocalfile;//保存路径
  16. privateintthreadcount;//线程数
  17. privateHandlermHandler;//消息处理器
  18. privateDaodao;//工具类
  19. privateintfileSize;//所要下载的文件的大小
  20. privateList<DownloadInfo>infos;//存放下载信息类的集合
  21. privatestaticfinalintINIT=1;//定义三种下载的状态:初始化状态,正在下载状态,暂停状态
  22. privatestaticfinalintDOWNLOADING=2;
  23. privatestaticfinalintPAUSE=3;
  24. privateintstate=INIT;
  25. publicDownloader(Stringurlstr,Stringlocalfile,intthreadcount,
  26. Contextcontext,HandlermHandler){
  27. this.urlstr=urlstr;
  28. this.localfile=localfile;
  29. this.threadcount=threadcount;
  30. this.mHandler=mHandler;
  31. dao=newDao(context);
  32. }
  33. /**
  34. *判断是否正在下载
  35. */
  36. publicbooleanisdownloading(){
  37. returnstate==DOWNLOADING;
  38. }
  39. /**
  40. *得到downloader里的信息
  41. *首先进行判断是否是第一次下载,如果是第一次就要进行初始化,并将下载器的信息保存到数据库中
  42. *如果不是第一次下载,那就要从数据库中读出之前下载的信息(起始位置,结束为止,文件大小等),并将下载信息返回给下载器
  43. */
  44. publicLoadInfogetDownloaderInfors(){
  45. if(isFirst(urlstr)){
  46. Log.v("TAG","isFirst");
  47. init();
  48. intrange=fileSize/threadcount;
  49. infos=newArrayList<DownloadInfo>();
  50. for(inti=0;i<threadcount-1;i++){
  51. DownloadInfoinfo=newDownloadInfo(i,i*range,(i+1)*range-1,0,urlstr);
  52. infos.add(info);
  53. }
  54. DownloadInfoinfo=newDownloadInfo(threadcount-1,(threadcount-1)*range,fileSize-1,0,urlstr);
  55. infos.add(info);
  56. //保存infos中的数据到数据库
  57. dao.saveInfos(infos);
  58. //创建一个LoadInfo对象记载下载器的具体信息
  59. LoadInfoloadInfo=newLoadInfo(fileSize,0,urlstr);
  60. returnloadInfo;
  61. }else{
  62. //得到数据库中已有的urlstr的下载器的具体信息
  63. infos=dao.getInfos(urlstr);
  64. Log.v("TAG","notisFirstsize="+infos.size());
  65. intsize=0;
  66. intcompeleteSize=0;
  67. for(DownloadInfoinfo:infos){
  68. compeleteSize+=info.getCompeleteSize();
  69. size+=info.getEndPos()-info.getStartPos()+1;
  70. }
  71. returnnewLoadInfo(size,compeleteSize,urlstr);
  72. }
  73. }
  74. /**
  75. *初始化
  76. */
  77. privatevoidinit(){
  78. try{
  79. URLurl=newURL(urlstr);
  80. HttpURLConnectionconnection=(HttpURLConnection)url.openConnection();
  81. connection.setConnectTimeout(5000);
  82. connection.setRequestMethod("GET");
  83. fileSize=connection.getContentLength();
  84. Filefile=newFile(localfile);
  85. if(!file.exists()){
  86. file.createNewFile();
  87. }
  88. //本地访问文件
  89. RandomAccessFileaccessFile=newRandomAccessFile(file,"rwd");
  90. accessFile.setLength(fileSize);
  91. accessFile.close();
  92. connection.disconnect();
  93. }catch(Exceptione){
  94. e.printStackTrace();
  95. }
  96. }
  97. /**
  98. *判断是否是第一次下载
  99. */
  100. privatebooleanisFirst(Stringurlstr){
  101. returndao.isHasInfors(urlstr);
  102. }
  103. /**
  104. *利用线程开始下载数据
  105. */
  106. publicvoiddownload(){
  107. if(infos!=null){
  108. if(state==DOWNLOADING)
  109. return;
  110. state=DOWNLOADING;
  111. for(DownloadInfoinfo:infos){
  112. newMyThread(info.getThreadId(),info.getStartPos(),
  113. info.getEndPos(),info.getCompeleteSize(),
  114. info.getUrl()).start();
  115. }
  116. }
  117. }
  118. publicclassMyThreadextendsThread{
  119. privateintthreadId;
  120. privateintstartPos;
  121. privateintendPos;
  122. privateintcompeleteSize;
  123. privateStringurlstr;
  124. publicMyThread(intthreadId,intstartPos,intendPos,
  125. intcompeleteSize,Stringurlstr){
  126. this.threadId=threadId;
  127. this.startPos=startPos;
  128. this.endPos=endPos;
  129. this.compeleteSize=compeleteSize;
  130. this.urlstr=urlstr;
  131. }
  132. @Override
  133. publicvoidrun(){
  134. HttpURLConnectionconnection=null;
  135. RandomAccessFilerandomAccessFile=null;
  136. InputStreamis=null;
  137. try{
  138. URLurl=newURL(urlstr);
  139. connection=(HttpURLConnection)url.openConnection();
  140. connection.setConnectTimeout(5000);
  141. connection.setRequestMethod("GET");
  142. //设置范围,格式为Range:bytesx-y;
  143. connection.setRequestProperty("Range","bytes="+(startPos+compeleteSize)+"-"+endPos);
  144. randomAccessFile=newRandomAccessFile(localfile,"rwd");
  145. randomAccessFile.seek(startPos+compeleteSize);
  146. Log.i("RG","connection--->>>"+connection);
  147. //将要下载的文件写到保存在保存路径下的文件中
  148. is=connection.getInputStream();
  149. byte[]buffer=newbyte[4096];
  150. intlength=-1;
  151. while((length=is.read(buffer))!=-1){
  152. randomAccessFile.write(buffer,0,length);
  153. compeleteSize+=length;
  154. //更新数据库中的下载信息
  155. dao.updataInfos(threadId,compeleteSize,urlstr);
  156. //用消息将下载信息传给进度条,对进度条进行更新
  157. Messagemessage=Message.obtain();
  158. message.what=1;
  159. message.obj=urlstr;
  160. message.arg1=length;
  161. mHandler.sendMessage(message);
  162. if(state==PAUSE){
  163. return;
  164. }
  165. }
  166. }catch(Exceptione){
  167. e.printStackTrace();
  168. }finally{
  169. try{
  170. is.close();
  171. randomAccessFile.close();
  172. connection.disconnect();
  173. dao.closeDb();
  174. }catch(Exceptione){
  175. e.printStackTrace();
  176. }
  177. }
  178. }
  179. }
  180. //删除数据库中urlstr对应的下载器信息
  181. publicvoiddelete(Stringurlstr){
  182. dao.delete(urlstr);
  183. }
  184. //设置暂停
  185. publicvoidpause(){
  186. state=PAUSE;
  187. }
  188. //重置下载状态
  189. publicvoidreset(){
  190. state=INIT;
  191. }
  192. }

Dao:

  1. packagecom.example.downloaderstopsart;
  2. importjava.util.ArrayList;
  3. importjava.util.List;
  4. importandroid.content.Context;
  5. importandroid.database.Cursor;
  6. importandroid.database.sqlite.SQLiteDatabase;
  7. publicclassDao{
  8. privateDBHelperdbHelper;
  9. publicDao(Contextcontext){
  10. dbHelper=newDBHelper(context);
  11. }
  12. /**
  13. *查看数据库中是否有数据
  14. */
  15. publicbooleanisHasInfors(Stringurlstr){
  16. SQLiteDatabasedatabase=dbHelper.getReadableDatabase();
  17. Stringsql="selectcount(*)fromdownload_infowhereurl=?";
  18. Cursorcursor=database.rawQuery(sql,newString[]{urlstr});
  19. cursor.moveToFirst();
  20. intcount=cursor.getInt(0);
  21. cursor.close();
  22. returncount==0;
  23. }
  24. /**
  25. *36*保存下载的具体信息37
  26. */
  27. publicvoidsaveInfos(List<DownloadInfo>infos){
  28. SQLiteDatabasedatabase=dbHelper.getWritableDatabase();
  29. for(DownloadInfoinfo:infos){
  30. Stringsql="insertintodownload_info(thread_id,start_pos,end_pos,compelete_size,url)values(?,?,?,?,?)";
  31. Object[]bindArgs={info.getThreadId(),info.getStartPos(),
  32. info.getEndPos(),info.getCompeleteSize(),info.getUrl()};
  33. database.execSQL(sql,bindArgs);
  34. }
  35. }
  36. /**
  37. *得到下载具体信息
  38. */
  39. publicList<DownloadInfo>getInfos(Stringurlstr){
  40. List<DownloadInfo>list=newArrayList<DownloadInfo>();
  41. SQLiteDatabasedatabase=dbHelper.getReadableDatabase();
  42. Stringsql="selectthread_id,start_pos,end_pos,compelete_size,urlfromdownload_infowhereurl=?";
  43. Cursorcursor=database.rawQuery(sql,newString[]{urlstr});
  44. while(cursor.moveToNext()){
  45. DownloadInfoinfo=newDownloadInfo(cursor.getInt(0),
  46. cursor.getInt(1),cursor.getInt(2),cursor.getInt(3),
  47. cursor.getString(4));
  48. list.add(info);
  49. }
  50. cursor.close();
  51. returnlist;
  52. }
  53. /**
  54. *更新数据库中的下载信息
  55. */
  56. publicvoidupdataInfos(intthreadId,intcompeleteSize,Stringurlstr){
  57. SQLiteDatabasedatabase=dbHelper.getReadableDatabase();
  58. Stringsql="updatedownload_infosetcompelete_size=?wherethread_id=?andurl=?";
  59. Object[]bindArgs={compeleteSize,threadId,urlstr};
  60. database.execSQL(sql,bindArgs);
  61. }
  62. /**
  63. *关闭数据库
  64. */
  65. publicvoidcloseDb(){
  66. dbHelper.close();
  67. }
  68. /**
  69. *下载完成后删除数据库中的数据
  70. */
  71. publicvoiddelete(Stringurl){
  72. SQLiteDatabasedatabase=dbHelper.getReadableDatabase();
  73. database.delete("download_info","url=?",newString[]{url});
  74. database.close();
  75. }
  76. }

xml如下:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"
  4. android:layout_width="fill_parent"
  5. android:layout_height="fill_parent"
  6. android:id="@+id/llRoot">
  7. <ListViewandroid:id="@android:id/list"
  8. android:layout_width="fill_parent"
  9. android:layout_height="fill_parent">
  10. </ListView>
  11. </LinearLayout>

item_list.xml:

  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="wrap_content"
  5. android:orientation="vertical">
  6. <LinearLayout
  7. android:layout_width="fill_parent"
  8. android:layout_height="wrap_content"
  9. android:layout_marginBottom="5dip"
  10. android:orientation="horizontal">
  11. <TextView
  12. android:id="@+id/tv_resouce_name"
  13. android:layout_width="fill_parent"
  14. android:layout_height="wrap_content"
  15. android:layout_weight="1"/>
  16. <Button
  17. android:id="@+id/btn_start"
  18. android:layout_width="fill_parent"
  19. android:layout_height="wrap_content"
  20. android:layout_weight="1"
  21. android:onClick="startDownload"
  22. android:text="下载"/>
  23. <Button
  24. android:id="@+id/btn_pause"
  25. android:layout_width="fill_parent"
  26. android:layout_height="wrap_content"
  27. android:layout_weight="1"
  28. android:onClick="pauseDownload"
  29. android:text="暂停"/>
  30. </LinearLayout>
  31. </LinearLayout>

记得加权限:
  1. <uses-permissionandroid:name="android.permission.INTERNET"/>
  2.  <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

还有在3.0以上的版本记得加上这句话:
  1. StrictMode.setThreadPolicy(newStrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
  2. StrictMode.setVmPolicy(newStrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());

效果图如下:

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics