Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android進階:實現多線程下載文件

Android進階:實現多線程下載文件

編輯:Android開發實例

多線程下載大概思路就是通過Range 屬性實現文件分段,然後用RandomAccessFile 來讀寫文件,最終合並為一個文件

 

首先看下效果圖

 

 

創建工程 ThreadDemo

 

首先布局文件 threaddemo.xml

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns: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.     > 
  7. <TextView    
  8.     android:layout_width="fill_parent"   
  9.     android:layout_height="wrap_content"   
  10.     android:text="下載地址" 
  11.     /> 
  12. <TextView 
  13.     android:id="@+id/downloadurl" 
  14.     android:layout_width="fill_parent"   
  15.     android:layout_height="wrap_content"   
  16.     android:lines="5" 
  17.     /> 
  18. <TextView    
  19.     android:layout_width="fill_parent"   
  20.     android:layout_height="wrap_content"   
  21.     android:text="線程數" 
  22.     /> 
  23. <EditText 
  24.     android:id="@+id/downloadnum" 
  25.     android:layout_width="fill_parent"   
  26.     android:layout_height="wrap_content"   
  27.     /> 
  28. <ProgressBar 
  29.     android:id="@+id/downloadProgressBar" 
  30.     android:layout_width="fill_parent"   
  31.     style="?android:attr/progressBarStyleHorizontal" 
  32.     android:layout_height="wrap_content"   
  33.     /> 
  34. <TextView 
  35.     android:id="@+id/downloadinfo" 
  36.     android:layout_width="fill_parent"   
  37.     android:layout_height="wrap_content"   
  38.     android:text="下載進度 0" 
  39.     /> 
  40. <Button 
  41.     android:id="@+id/downloadbutton" 
  42.     android:layout_width="wrap_content"   
  43.     android:layout_height="wrap_content"   
  44.     android:text="開始下載" 
  45.     /> 
  46. </LinearLayout> 

 

主界面 Acitivity

 

 

  1. public class ThreadDownloadDemo extends Activity {  
  2.    
  3.     private TextView downloadurl;  
  4.     private EditText downloadnum;  
  5.     private Button downloadbutton;  
  6.     private ProgressBar downloadProgressBar;  
  7.     private TextView downloadinfo;  
  8.     private int downloadedSize = 0;  
  9.     private int fileSize = 0;  
  10.       
  11.     private long downloadtime;  
  12.    
  13.     @Override 
  14.     public void onCreate(Bundle savedInstanceState) {  
  15.         super.onCreate(savedInstanceState);  
  16.         setContentView(R.layout.threaddemo);  
  17.    
  18.         downloadurl = (TextView) findViewById(R.id.downloadurl);  
  19.         downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3");  
  20.         downloadnum = (EditText) findViewById(R.id.downloadnum);  
  21.         downloadinfo = (TextView) findViewById(R.id.downloadinfo);  
  22.         downloadbutton = (Button) findViewById(R.id.downloadbutton);  
  23.         downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);  
  24.         downloadProgressBar.setVisibility(View.VISIBLE);  
  25.         downloadProgressBar.setMax(100);  
  26.         downloadProgressBar.setProgress(0);  
  27.         downloadbutton.setOnClickListener(new OnClickListener() {  
  28.             public void onClick(View v) {  
  29.                 download();  
  30.                 downloadtime = SystemClock.currentThreadTimeMillis();  
  31.             }  
  32.         });  
  33.     }  
  34.    
  35.     private void download() {  
  36.         // 獲取SD卡目錄  
  37.         String dowloadDir = Environment.getExternalStorageDirectory()  
  38.                 + "/threaddemodownload/";  
  39.         File file = new File(dowloadDir);  
  40.         //創建下載目錄  
  41.         if (!file.exists()) {  
  42.             file.mkdirs();  
  43.         }  
  44.           
  45.         //讀取下載線程數,如果為空,則單線程下載  
  46.         int downloadTN = Integer.valueOf("".equals(downloadnum.getText()  
  47.                 .toString()) ? "1" : downloadnum.getText().toString());  
  48.         String fileName = "hetang.mp3";  
  49.         //開始下載前把下載按鈕設置為不可用  
  50.         downloadbutton.setClickable(false);  
  51.         //進度條設為0  
  52.         downloadProgressBar.setProgress(0);  
  53.         //啟動文件下載線程  
  54.         new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", Integer  
  55.                 .valueOf(downloadTN), dowloadDir + fileName).start();  
  56.     }  
  57.    
  58.     Handler handler = new Handler() {  
  59.         @Override 
  60.         public void handleMessage(Message msg) {  
  61.             //當收到更新視圖消息時,計算已完成下載百分比,同時更新進度條信息  
  62.             int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();  
  63.             if (progress == 100) {  
  64.                 downloadbutton.setClickable(true);  
  65.                 downloadinfo.setText("下載完成!");  
  66.                 Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this)  
  67.                     .setTitle("提示信息")  
  68.                     .setMessage("下載完成,總用時為:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒")  
  69.                     .setNegativeButton("確定", new DialogInterface.OnClickListener(){  
  70.                         @Override 
  71.                         public void onClick(DialogInterface dialog, int which) {  
  72.                             dialog.dismiss();  
  73.                         }  
  74.                     })  
  75.                     .create();  
  76.                 mdialog.show();  
  77.             } else {  
  78.                 downloadinfo.setText("當前進度:" + progress + "%");  
  79.             }  
  80.             downloadProgressBar.setProgress(progress);  
  81.         }  
  82.    
  83.     };  
  84.    
  85.       
  86.     public class downloadTask extends Thread {  
  87.         private int blockSize, downloadSizeMore;  
  88.         private int threadNum = 5;  
  89.         String urlStr, threadNo, fileName;  
  90.    
  91.         public downloadTask(String urlStr, int threadNum, String fileName) {  
  92.             this.urlStr = urlStr;  
  93.             this.threadNum = threadNum;  
  94.             this.fileName = fileName;  
  95.         }  
  96.    
  97.         @Override 
  98.         public void run() {  
  99.             FileDownloadThread[] fds = new FileDownloadThread[threadNum];  
  100.             try {  
  101.                 URL url = new URL(urlStr);  
  102.                 URLConnection conn = url.openConnection();  
  103.                 //防止返回-1  
  104.                 InputStream in = conn.getInputStream();  
  105.                 //獲取下載文件的總大小  
  106.                 fileSize = conn.getContentLength();  
  107.                 Log.i("bb", "======================fileSize:"+fileSize);  
  108.                 //計算每個線程要下載的數據量  
  109.                 blockSize = fileSize / threadNum;  
  110.                 // 解決整除後百分比計算誤差  
  111.                 downloadSizeMore = (fileSize % threadNum);  
  112.                 File file = new File(fileName);  
  113.                 for (int i = 0; i < threadNum; i++) {  
  114.                     Log.i("bb", "======================i:"+i);  
  115.                     //啟動線程,分別下載自己需要下載的部分  
  116.                     FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);  
  117.                     fdt.setName("Thread" + i);  
  118.                     fdt.start();  
  119.                     fds[i] = fdt;  
  120.                 }  
  121.                 boolean finished = false;  
  122.                 while (!finished) {  
  123.                     // 先把整除的余數搞定  
  124.                     downloadedSize = downloadSizeMore;  
  125.                     finished = true;  
  126.                     for (int i = 0; i < fds.length; i++) {  
  127.                         downloadedSize += fds[i].getDownloadSize();  
  128.                         if (!fds[i].isFinished()) {  
  129.                             finished = false;  
  130.                         }  
  131.                     }  
  132.                     handler.sendEmptyMessage(0);  
  133.                     //線程暫停一秒  
  134.                     sleep(1000);  
  135.                 }  
  136.             } catch (Exception e) {  
  137.                 e.printStackTrace();  
  138.             }  
  139.    
  140.         }  
  141.     }  

 

這裡啟動線程將文件分割為幾個部分,每一個部分再啟動一個線程去下載數據

 

下載文件的線程

 

  1. public class FileDownloadThread extends Thread{  
  2.     private static final int BUFFER_SIZE=1024;  
  3.     private URL url;  
  4.     private File file;  
  5.     private int startPosition;  
  6.     private int endPosition;  
  7.     private int curPosition;  
  8.     //標識當前線程是否下載完成  
  9.     private boolean finished=false;  
  10.     private int downloadSize=0;  
  11.     public FileDownloadThread(URL url,File file,int startPosition,int endPosition){  
  12.         this.url=url;  
  13.         this.file=file;  
  14.         this.startPosition=startPosition;  
  15.         this.curPosition=startPosition;  
  16.         this.endPosition=endPosition;  
  17.     }  
  18.     @Override 
  19.     public void run() {  
  20.         BufferedInputStream bis = null;  
  21.         RandomAccessFile fos = null;                                                 
  22.         byte[] buf = new byte[BUFFER_SIZE];  
  23.         URLConnection con = null;  
  24.         try {  
  25.             con = url.openConnection();  
  26.             con.setAllowUserInteraction(true);  
  27.             //設置當前線程下載的起止點  
  28.             con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);  
  29.             Log.i("bb", Thread.currentThread().getName()+"  bytes=" + startPosition + "-" + endPosition);  
  30.             //使用java中的RandomAccessFile 對文件進行隨機讀寫操作  
  31.             fos = new RandomAccessFile(file, "rw");  
  32.             //設置寫文件的起始位置  
  33.             fos.seek(startPosition);  
  34.             bis = new BufferedInputStream(con.getInputStream());    
  35.             //開始循環以流的形式讀寫文件  
  36.             while (curPosition < endPosition) {  
  37.                 int len = bis.read(buf, 0, BUFFER_SIZE);                  
  38.                 if (len == -1) {  
  39.                     break;  
  40.                 }  
  41.                 fos.write(buf, 0, len);  
  42.                 curPosition = curPosition + len;  
  43.                 if (curPosition > endPosition) {  
  44.                     downloadSize+=len - (curPosition - endPosition) + 1;  
  45.                 } else {  
  46.                     downloadSize+=len;  
  47.                 }  
  48.             }  
  49.             //下載完成設為true  
  50.             this.finished = true;  
  51.             bis.close();  
  52.             fos.close();  
  53.         } catch (IOException e) {  
  54.             e.printStackTrace();  
  55.         }  
  56.     }  
  57.    
  58.     public boolean isFinished(){  
  59.         return finished;  
  60.     }  
  61.    
  62.     public int getDownloadSize() {  
  63.         return downloadSize;  
  64.     }  

 

這裡通過RandomAccessFile 的seek方法定位到相應的位置 並實時記錄下載量

 

當然這裡需要聯網和訪問SD卡 所以要加上相應的權限

  1. <uses-permission android:name="android.permission.INTERNET" /> 
  2.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved