很多时候我们需要在Android设备上下载远程服务器上的文件进安装,前两天晚上我看到一个视频,写了两个晚上,大概理解一下。 直接通过Android提供的Http类访问远程服务器,这里AndroidHttpClient是SDK 2.2中新出的方法,

下载断点文件。

下面让我们看一下图先。

        
  1. 让我们看一下代码的实现方法。
  2. packagecom.smart.db;
  3. importjava.util.HashMap;
  4. importjava.util.Map;
  5. importandroid.content.Context;
  6. importandroid.database.Cursor;
  7. importandroid.database.sqlite.SQLiteDatabase;
  8. /**
  9. *业务bean
  10. *
  11. */
  12. publicclassFileService{
  13. privateDBOpenHelperopenHelper;
  14. publicFileService(Contextcontext){
  15. openHelper=newDBOpenHelper(context);
  16. }
  17. /**
  18. *获取每条线程已经下载的文件长度
  19. *@parampath
  20. *@return
  21. */
  22. publicMap<Integer,Integer>getData(Stringpath){
  23. SQLiteDatabasedb=openHelper.getReadableDatabase();
  24. Cursorcursor=db.rawQuery("selectthreadid,downlengthfromSmartFileDownlogwheredownpath=?",newString[]{path});
  25. Map<Integer,Integer>data=newHashMap<Integer,Integer>();
  26. while(cursor.moveToNext()){
  27. data.put(cursor.getInt(0),cursor.getInt(1));
  28. }
  29. cursor.close();
  30. db.close();
  31. returndata;
  32. }
  33. /**
  34. *保存每条线程已经下载的文件长度
  35. *@parampath
  36. *@parammap
  37. */
  38. publicvoidsave(Stringpath,Map<Integer,Integer>map){//intthreadid,intposition
  39. SQLiteDatabasedb=openHelper.getWritableDatabase();
  40. db.beginTransaction();
  41. try{
  42. for(Map.Entry<Integer,Integer>entry:map.entrySet()){
  43. db.execSQL("insertintoSmartFileDownlog(downpath,threadid,downlength)values(?,?,?)",
  44. newObject[]{path,entry.getKey(),entry.getValue()});
  45. }
  46. db.setTransactionSuccessful();
  47. }finally{
  48. db.endTransaction();
  49. }
  50. db.close();
  51. }
  52. /**
  53. *实时更新每条线程已经下载的文件长度
  54. *@parampath
  55. *@parammap
  56. */
  57. publicvoidupdate(Stringpath,Map<Integer,Integer>map){
  58. SQLiteDatabasedb=openHelper.getWritableDatabase();
  59. db.beginTransaction();
  60. try{
  61. for(Map.Entry<Integer,Integer>entry:map.entrySet()){
  62. db.execSQL("updateSmartFileDownlogsetdownlength=?wheredownpath=?andthreadid=?",
  63. newObject[]{entry.getValue(),path,entry.getKey()});
  64. }
  65. db.setTransactionSuccessful();
  66. }finally{
  67. db.endTransaction();
  68. }
  69. db.close();
  70. }
  71. /**
  72. *当文件下载完成后,删除对应的下载记录
  73. *@parampath
  74. */
  75. publicvoiddelete(Stringpath){
  76. SQLiteDatabasedb=openHelper.getWritableDatabase();
  77. db.execSQL("deletefromSmartFileDownlogwheredownpath=?",newObject[]{path});
  78. db.close();
  79. }
  80. }
  81. packagecom.smart.impl;
  82. importjava.io.File;
  83. importjava.io.RandomAccessFile;
  84. importjava.net.HttpURLConnection;
  85. importjava.net.URL;
  86. importjava.util.LinkedHashMap;
  87. importjava.util.Map;
  88. importjava.util.UUID;
  89. importjava.util.concurrent.ConcurrentHashMap;
  90. importjava.util.regex.Matcher;
  91. importjava.util.regex.Pattern;
  92. importandroid.content.Context;
  93. importandroid.util.Log;
  94. importcom.smart.db.FileService;
  95. /**
  96. *文件下载器
  97. *@author[email protected]
  98. */
  99. publicclassSmartFileDownloader{
  100. privatestaticfinalStringTAG="SmartFileDownloader";
  101. privateContextcontext;
  102. privateFileServicefileService;
  103. /*已下载文件长度*/
  104. privateintdownloadSize=0;
  105. /*原始文件长度*/
  106. privateintfileSize=0;
  107. /*线程数*/
  108. privateSmartDownloadThread[]threads;
  109. /*本地保存文件*/
  110. privateFilesaveFile;
  111. /*缓存各线程下载的长度*/
  112. privateMap<Integer,Integer>data=newConcurrentHashMap<Integer,Integer>();
  113. /*每条线程下载的长度*/
  114. privateintblock;
  115. /*下载路径*/
  116. privateStringdownloadUrl;
  117. /**
  118. *获取线程数
  119. */
  120. publicintgetThreadSize(){
  121. returnthreads.length;
  122. }
  123. /**
  124. *获取文件大小
  125. *@return
  126. */
  127. publicintgetFileSize(){
  128. returnfileSize;
  129. }
  130. /**
  131. *累计已下载大小
  132. *@paramsize
  133. */
  134. protectedsynchronizedvoidappend(intsize){
  135. downloadSize+=size;
  136. }
  137. /**
  138. *更新指定线程最后下载的位置
  139. *@paramthreadId线程id
  140. *@parampos最后下载的位置
  141. */
  142. protectedvoidupdate(intthreadId,intpos){
  143. this.data.put(threadId,pos);
  144. }
  145. /**
  146. *保存记录文件
  147. */
  148. protectedsynchronizedvoidsaveLogFile(){
  149. this.fileService.update(this.downloadUrl,this.data);
  150. }
  151. /**
  152. *构建文件下载器
  153. *@paramdownloadUrl下载路径
  154. *@paramfileSaveDir文件保存目录
  155. *@paramthreadNum下载线程数
  156. */
  157. publicSmartFileDownloader(Contextcontext,StringdownloadUrl,FilefileSaveDir,intthreadNum){
  158. try{
  159. this.context=context;
  160. this.downloadUrl=downloadUrl;
  161. fileService=newFileService(this.context);
  162. URLurl=newURL(this.downloadUrl);
  163. if(!fileSaveDir.exists())fileSaveDir.mkdirs();
  164. this.threads=newSmartDownloadThread[threadNum];
  165. HttpURLConnectionconn=(HttpURLConnection)url.openConnection();
  166. conn.setConnectTimeout(5*1000);
  167. conn.setRequestMethod("GET");
  168. conn.setRequestProperty("Accept","image/gif,image/jpeg,image/pjpeg,image/pjpeg,application/x-shockwave-flash,application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/*");
  169. conn.setRequestProperty("Accept-Language","zh-CN");
  170. conn.setRequestProperty("Referer",downloadUrl);
  171. conn.setRequestProperty("Charset","UTF-8");
  172. conn.setRequestProperty("User-Agent","Mozilla/4.0(compatible;MSIE8.0;WindowsNT5.2;Trident/4.0;.NETCLR1.1.4322;.NETCLR2.0.50727;.NETCLR3.0.04506.30;.NETCLR3.0.4506.2152;.NETCLR3.5.30729)");
  173. conn.setRequestProperty("Connection","Keep-Alive");
  174. conn.connect();
  175. printResponseHeader(conn);
  176. if(conn.getResponseCode()==200){
  177. this.fileSize=conn.getContentLength();//根据响应获取文件大小
  178. if(this.fileSize<=0)thrownewRuntimeException("Unkownfilesize");
  179. Stringfilename=getFileName(conn);
  180. this.saveFile=newFile(fileSaveDir,filename);/*保存文件*/
  181. Map<Integer,Integer>logdata=fileService.getData(downloadUrl);
  182. if(logdata.size()>0){
  183. for(Map.Entry<Integer,Integer>entry:logdata.entrySet())
  184. data.put(entry.getKey(),entry.getValue());
  185. }
  186. this.block=(this.fileSize%this.threads.length)==0?this.fileSize/this.threads.length:this.fileSize/this.threads.length+1;
  187. if(this.data.size()==this.threads.length){
  188. for(inti=0;i<this.threads.length;i++){
  189. this.downloadSize+=this.data.get(i+1);
  190. }
  191. print("已经下载的长度"+this.downloadSize);
  192. }
  193. }else{
  194. thrownewRuntimeException("servernoresponse");
  195. }
  196. }catch(Exceptione){
  197. print(e.toString());
  198. thrownewRuntimeException("don'tconnectionthisurl");
  199. }
  200. }
  201. /**
  202. *获取文件名
  203. */
  204. privateStringgetFileName(HttpURLConnectionconn){
  205. Stringfilename=this.downloadUrl.substring(this.downloadUrl.lastIndexOf('/')+1);
  206. if(filename==null||"".equals(filename.trim())){//如果获取不到文件名称
  207. for(inti=0;;i++){
  208. Stringmine=conn.getHeaderField(i);
  209. if(mine==null)break;
  210. if("content-disposition".equals(conn.getHeaderFieldKey(i).toLowerCase())){
  211. Matcherm=Pattern.compile(".*filename=(.*)").matcher(mine.toLowerCase());
  212. if(m.find())returnm.group(1);
  213. }
  214. }
  215. filename=UUID.randomUUID()+".tmp";//默认取一个文件名
  216. }
  217. returnfilename;
  218. }
  219. /**
  220. *开始下载文件
  221. *@paramlistener监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null
  222. *@return已下载文件大小
  223. *@throwsException
  224. */
  225. publicintdownload(SmartDownloadProgressListenerlistener)throwsException{
  226. try{
  227. RandomAccessFilerandOut=newRandomAccessFile(this.saveFile,"rw");
  228. if(this.fileSize>0)randOut.setLength(this.fileSize);
  229. randOut.close();
  230. URLurl=newURL(this.downloadUrl);
  231. if(this.data.size()!=this.threads.length){
  232. this.data.clear();//清除数据
  233. for(inti=0;i<this.threads.length;i++){
  234. this.data.put(i+1,0);
  235. }
  236. }
  237. for(inti=0;i<this.threads.length;i++){
  238. intdownLength=this.data.get(i+1);
  239. if(downLength<this.block&&this.downloadSize<this.fileSize){//该线程未完成下载时,继续下载
  240. this.threads=newSmartDownloadThread(this,url,this.saveFile,this.block,this.data.get(i+1),i+1);
  241. this.threads.setPriority(7);
  242. this.threads.start();
  243. }else{
  244. this.threads=null;
  245. }
  246. }
  247. this.fileService.save(this.downloadUrl,this.data);
  248. booleannotFinish=true;//下载未完成
  249. while(notFinish){//循环判断是否下载完毕
  250. Thread.sleep(900);
  251. notFinish=false;//假定下载完成
  252. for(inti=0;i<this.threads.length;i++){
  253. if(this.threads!=null&&!this.threads.isFinish()){
  254. notFinish=true;//下载没有完成
  255. if(this.threads.getDownLength()==-1){//如果下载失败,再重新下载
  256. this.threads=newSmartDownloadThread(this,url,this.saveFile,this.block,this.data.get(i+1),i+1);
  257. this.threads.setPriority(7);
  258. this.threads.start();
  259. }
  260. }
  261. }
  262. if(listener!=null)listener.onDownloadSize(this.downloadSize);
  263. }
  264. fileService.delete(this.downloadUrl);
  265. }catch(Exceptione){
  266. print(e.toString());
  267. thrownewException("filedownloadfail");
  268. }
  269. returnthis.downloadSize;
  270. }
  271. /**
  272. *获取Http响应头字段
  273. *@paramhttp
  274. *@return
  275. */
  276. publicstaticMap<String,String>getHttpResponseHeader(HttpURLConnectionhttp){
  277. Map<String,String>header=newLinkedHashMap<String,String>();
  278. for(inti=0;;i++){
  279. Stringmine=http.getHeaderField(i);
  280. if(mine==null)break;
  281. header.put(http.getHeaderFieldKey(i),mine);
  282. }
  283. returnheader;
  284. }
  285. /**
  286. *打印Http头字段
  287. *@paramhttp
  288. */
  289. publicstaticvoidprintResponseHeader(HttpURLConnectionhttp){
  290. Map<String,String>header=getHttpResponseHeader(http);
  291. for(Map.Entry<String,String>entry:header.entrySet()){
  292. Stringkey=entry.getKey()!=null?entry.getKey()+":":"";
  293. print(key+entry.getValue());
  294. }
  295. }
  296. //打印日志
  297. privatestaticvoidprint(Stringmsg){
  298. Log.i(TAG,msg);
  299. }
  300. }
  301. packagecom.smart.impl;
  302. importjava.io.File;
  303. importjava.io.InputStream;
  304. importjava.io.RandomAccessFile;
  305. importjava.net.HttpURLConnection;
  306. importjava.net.URL;
  307. importandroid.util.Log;
  308. publicclassSmartDownloadThreadextendsThread{
  309. privatestaticfinalStringTAG="SmartDownloadThread";
  310. privateFilesaveFile;
  311. privateURLdownUrl;
  312. privateintblock;
  313. /**下载开始位置*/
  314. privateintthreadId=-1;
  315. privateintdownLength;
  316. privatebooleanfinish=false;
  317. privateSmartFileDownloaderdownloader;
  318. publicSmartDownloadThread(SmartFileDownloaderdownloader,URLdownUrl,FilesaveFile,intblock,intdownLength,intthreadId){
  319. this.downUrl=downUrl;
  320. this.saveFile=saveFile;
  321. this.block=block;
  322. this.downloader=downloader;
  323. this.threadId=threadId;
  324. this.downLength=downLength;
  325. }
  326. @Override
  327. publicvoidrun(){
  328. if(downLength<block){//未下载完成
  329. try{
  330. HttpURLConnectionhttp=(HttpURLConnection)downUrl.openConnection();
  331. http.setConnectTimeout(5*1000);
  332. http.setRequestMethod("GET");
  333. http.setRequestProperty("Accept","image/gif,image/jpeg,image/pjpeg,image/pjpeg,application/x-shockwave-flash,application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/*");
  334. http.setRequestProperty("Accept-Language","zh-CN");
  335. http.setRequestProperty("Referer",downUrl.toString());
  336. http.setRequestProperty("Charset","UTF-8");
  337. intstartPos=block*(threadId-1)+downLength;//开始位置
  338. intendPos=block*threadId-1;//结束位置
  339. http.setRequestProperty("Range","bytes="+startPos+"-"+endPos);//设置获取实体数据的范围
  340. http.setRequestProperty("User-Agent","Mozilla/4.0(compatible;MSIE8.0;WindowsNT5.2;Trident/4.0;.NETCLR1.1.4322;.NETCLR2.0.50727;.NETCLR3.0.04506.30;.NETCLR3.0.4506.2152;.NETCLR3.5.30729)");
  341. http.setRequestProperty("Connection","Keep-Alive");
  342. InputStreaminStream=http.getInputStream();
  343. byte[]buffer=newbyte[1024];
  344. intoffset=0;
  345. print("Thread"+this.threadId+"startdownloadfromposition"+startPos);
  346. RandomAccessFilethreadfile=newRandomAccessFile(this.saveFile,"rwd");
  347. threadfile.seek(startPos);
  348. while((offset=inStream.read(buffer,0,1024))!=-1){
  349. threadfile.write(buffer,0,offset);
  350. downLength+=offset;
  351. downloader.update(this.threadId,downLength);
  352. downloader.saveLogFile();
  353. downloader.append(offset);
  354. }
  355. threadfile.close();
  356. inStream.close();
  357. print("Thread"+this.threadId+"downloadfinish");
  358. this.finish=true;
  359. }catch(Exceptione){
  360. this.downLength=-1;
  361. print("Thread"+this.threadId+":"+e);
  362. }
  363. }
  364. }
  365. privatestaticvoidprint(Stringmsg){
  366. Log.i(TAG,msg);
  367. }
  368. /**
  369. *下载是否完成
  370. *@return
  371. */
  372. publicbooleanisFinish(){
  373. returnfinish;
  374. }
  375. /**
  376. *已经下载的内容大小
  377. *@return如果返回值为-1,代表下载失败
  378. */
  379. publiclonggetDownLength(){
  380. returndownLength;
  381. }
  382. }
  383. packagecom.smart.activoty.download;
  384. importjava.io.File;
  385. importandroid.app.Activity;
  386. importandroid.os.Bundle;
  387. importandroid.os.Environment;
  388. importandroid.os.Handler;
  389. importandroid.os.Message;
  390. importandroid.view.View;
  391. importandroid.widget.Button;
  392. importandroid.widget.EditText;
  393. importandroid.widget.ProgressBar;
  394. importandroid.widget.TextView;
  395. importandroid.widget.Toast;
  396. importcom.smart.impl.SmartDownloadProgressListener;
  397. importcom.smart.impl.SmartFileDownloader;
  398. publicclassSmartDownloadActivityextendsActivity{
  399. privateProgressBardownloadbar;
  400. privateEditTextpathText;
  401. privateTextViewresultView;
  402. privateHandlerhandler=newHandler(){
  403. @Override//信息
  404. publicvoidhandleMessage(Messagemsg){
  405. switch(msg.what){
  406. case1:
  407. intsize=msg.getData().getInt("size");
  408. downloadbar.setProgress(size);
  409. floatresult=(float)downloadbar.getProgress()/(float)downloadbar.getMax();
  410. intp=(int)(result*100);
  411. resultView.setText(p+"%");
  412. if(downloadbar.getProgress()==downloadbar.getMax())
  413. Toast.makeText(SmartDownloadActivity.this,R.string.success,1).show();
  414. break;
  415. case-1:
  416. Toast.makeText(SmartDownloadActivity.this,R.string.error,1).show();
  417. break;
  418. }
  419. }
  420. };
  421. @Override
  422. publicvoidonCreate(BundlesavedInstanceState){
  423. super.onCreate(savedInstanceState);
  424. setContentView(R.layout.main);
  425. Buttonbutton=(Button)this.findViewById(R.id.button);
  426. downloadbar=(ProgressBar)this.findViewById(R.id.downloadbar);
  427. pathText=(EditText)this.findViewById(R.id.path);
  428. resultView=(TextView)this.findViewById(R.id.result);
  429. button.setOnClickListener(newView.OnClickListener(){
  430. @Override
  431. publicvoidonClick(Viewv){
  432. Stringpath=pathText.getText().toString();
  433. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
  434. Filedir=Environment.getExternalStorageDirectory();//文件保存目录
  435. download(path,dir);
  436. }else{
  437. Toast.makeText(SmartDownloadActivity.this,R.string.sdcarderror,1).show();
  438. }
  439. }
  440. });
  441. }
  442. //对于UI控件的更新只能由主线程(UI线程)负责,如果在非UI线程更新UI控件,更新的结果不会反映在屏幕上,某些控件还会出错
  443. privatevoiddownload(finalStringpath,finalFiledir){
  444. newThread(newRunnable(){
  445. @Override
  446. publicvoidrun(){
  447. try{
  448. SmartFileDownloaderloader=newSmartFileDownloader(SmartDownloadActivity.this,path,dir,3);
  449. intlength=loader.getFileSize();//获取文件的长度
  450. downloadbar.setMax(length);
  451. loader.download(newSmartDownloadProgressListener(){
  452. @Override
  453. publicvoidonDownloadSize(intsize){//可以实时得到文件下载的长度
  454. Messagemsg=newMessage();
  455. msg.what=1;
  456. msg.getData().putInt("size",size);
  457. handler.sendMessage(msg);
  458. }});
  459. }catch(Exceptione){
  460. Messagemsg=newMessage();//信息提示
  461. msg.what=-1;
  462. msg.getData().putString("error","下载失败");//如果下载错误,显示提示失败!
  463. handler.sendMessage(msg);
  464. }
  465. }
  466. }).start();//开始
  467. }
  468. }


更多相关文章

  1. android-pull方式解析xml文件以及XML文件的序列化
  2. android 实现左右滑动效果
  3. Android的Recovery中font_10x10.h字库文件制作
  4. android R cannot be resolved to a variable
  5. Android(安卓)APK反编译详解
  6. Android(安卓)面试题(5):谈谈 Handler 机制和原理?
  7. Android(安卓)Spinner
  8. APEX - Android(安卓)Q
  9. Android的Zipalign优化

随机推荐

  1. 获取Android(安卓)SDK 源代码并在Eclipse
  2. android TabHost导航切换实现方式
  3. android 兼容所有刘海屏的方案大全
  4. android:maxHeight,android:maxWidth失效
  5. Android(安卓)ListView 去除边缘阴影、选
  6. Android(安卓)UI Design
  7. 【读书笔记-《Android游戏编程之从零开始
  8. Android(安卓)系统UI设计规则
  9. android:gravity 和 android:layout_Grav
  10. Android之抽屉效果(自定义、GridView、Sli