posts - 189,comments - 115,trackbacks - 0

          [轉載:]  

          http://www.ideasandroid.com/?p=328

          本文將介紹在android平臺下如何實現多線程下載,大家都知道,android平臺使用java做為開發語言,所以java中支持的多線程下載方式在android平臺下都支持,其中主要有兩種方式可以實現多線程下載。

          一種方式是使用很多個線程分別下載文件的不同部分,最后把所有下載完的文件合并成一個文件。另一種方式是使用java為我們提供的RandomAccessFile類實現多線程的下載。

          從性能上分析,第二種方式的存取速度會慢一些,但開發起來較為容易,不需要進行合并文件等操作。本文將使用第二種方式來實現多線程下載,最終效果如下圖所示:

          第一步,我們先寫一個線程類,來完成對指定區域的數據進行下載,如下所示:

          package com.ideasandroid.demo;
           
          import java.io.BufferedInputStream;
          import java.io.File;
          import java.io.IOException;
          import java.io.RandomAccessFile;
          import java.net.URL;
          import java.net.URLConnection;
           
          import android.util.Log;
          /**
          *  Copyright (C) 2010 ideasandroid
          *  演示android多線程下載
          *  歡迎訪問http://www.ideasandroid.com
          *  讓程序開發不再那么神秘
          *
          *  單個下載線程
          */
          public class FileDownloadThread extends Thread{
          private static final int BUFFER_SIZE=1024;
          private URL url;
          private File file;
          private int startPosition;
          private int endPosition;
          private int curPosition;
          //用于標識當前線程是否下載完成
          private boolean finished=false;
          private int downloadSize=0;
          public FileDownloadThread(URL url,File file,int startPosition,int endPosition){
          this.url=url;
          this.file=file;
          this.startPosition=startPosition;
          this.curPosition=startPosition;
          this.endPosition=endPosition;
          }
          @Override
          public void run() {
          BufferedInputStream bis = null;
          RandomAccessFile fos = null;
          byte[] buf = new byte[BUFFER_SIZE];
          URLConnection con = null;
          try {
          con = url.openConnection();
          con.setAllowUserInteraction(true);
          //設置當前線程下載的起點,終點
          con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);
          //使用java中的RandomAccessFile 對文件進行隨機讀寫操作
          fos = new RandomAccessFile(file, "rw");
          //設置開始寫文件的位置
          fos.seek(startPosition);
          bis = new BufferedInputStream(con.getInputStream());
          //開始循環以流的形式讀寫文件
          while (curPosition < endPosition) {
          int len = bis.read(buf, 0, BUFFER_SIZE);
          if (len == -1) {
          break;
          }
          fos.write(buf, 0, len);
          curPosition = curPosition + len;
          if (curPosition > endPosition) {
          downloadSize+=len - (curPosition - endPosition) + 1;
          } else {
          downloadSize+=len;
          }
          }
          //下載完成設為true
          this.finished = true;
          bis.close();
          fos.close();
          } catch (IOException e) {
          Log.d(getName() +" Error:", e.getMessage());
          }
          }
           
          public boolean isFinished(){
          return finished;
          }
           
          public int getDownloadSize() {
          return downloadSize;
          }
          }

          接下來就是使用圖形界面來獲取需要下載的內容,并實時更新下載進度條,代碼如下所示:

          package com.ideasandroid.demo;
           
          import java.io.File;
          import java.net.URL;
          import java.net.URLConnection;
          import android.app.Activity;
          import android.os.Bundle;
          import android.os.Environment;
          import android.os.Handler;
          import android.os.Message;
          import android.view.View;
          import android.view.View.OnClickListener;
          import android.widget.Button;
          import android.widget.EditText;
          import android.widget.ProgressBar;
          import android.widget.TextView;
          /**
          *  Copyright (C) 2010 ideasandroid
          *  演示android多線程下載
          *  歡迎訪問http://www.ideasandroid.com
          *  讓程序開發不再那么神秘
          */
          public class FileDownloadDemo extends Activity {
           
          private EditText downloadUrl;
          private EditText downloadFileName;
          private EditText downloadThreadNum;
          private Button downloadBt;
          private ProgressBar downloadProgressBar;
          private TextView progressMessage;
          private int downloadedSize = 0;
          private int fileSize = 0;
           
          @Override
          public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
           
          downloadUrl = (EditText) findViewById(R.id.downloadUrl);
          downloadFileName = (EditText) findViewById(R.id.downloadFileName);
          downloadThreadNum = (EditText) findViewById(R.id.downloadThreadNum);
          progressMessage = (TextView) findViewById(R.id.progressMessage);
          downloadBt = (Button) findViewById(R.id.downloadBt);
          downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);
          downloadProgressBar.setVisibility(View.VISIBLE);
          downloadProgressBar.setMax(100);
          downloadProgressBar.setProgress(0);
          downloadBt.setOnClickListener(new OnClickListener() {
          public void onClick(View v) {
          download();
          }
          });
          }
           
          private void download() {
          // 獲取SD卡目錄
          String dowloadDir = Environment.getExternalStorageDirectory()
          + "/ideasdownload/";
          File file = new File(dowloadDir);
          //創建下載目錄
          if (!file.exists()) {
          file.mkdirs();
          }
           
          //讀取下載線程數,如果為空,則單線程下載
          int downloadTN = Integer.valueOf("".equals(downloadThreadNum.getText()
          .toString()) ? "1" : downloadThreadNum.getText().toString());
          //如果下載文件名為空則獲取Url尾為文件名
          int fileNameStart = downloadUrl.getText().toString().lastIndexOf("/");
          String fileName = "".equals(downloadFileName.getText().toString()) ? downloadUrl
          .getText().toString().substring(fileNameStart)
          : downloadFileName.getText().toString();
          //開始下載前把下載按鈕設置為不可用
          downloadBt.setClickable(false);
          //進度條設為0
          downloadProgressBar.setProgress(0);
          //啟動文件下載線程
          new downloadTask(downloadUrl.getText().toString(), Integer
          .valueOf(downloadTN), dowloadDir + fileName).start();
          }
           
          Handler handler = new Handler() {
          @Override
          public void handleMessage(Message msg) {
          //當收到更新視圖消息時,計算已完成下載百分比,同時更新進度條信息
          int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();
          if (progress == 100) {
          downloadBt.setClickable(true);
          progressMessage.setText("下載完成!");
          } else {
          progressMessage.setText("當前進度:" + progress + "%");
          }
          downloadProgressBar.setProgress(progress);
          }
           
          };
           
          /**
          * @author ideasandroid
          * 主下載線程
          */
          public class downloadTask extends Thread {
          private int blockSize, downloadSizeMore;
          private int threadNum = 5;
          String urlStr, threadNo, fileName;
           
          public downloadTask(String urlStr, int threadNum, String fileName) {
          this.urlStr = urlStr;
          this.threadNum = threadNum;
          this.fileName = fileName;
          }
           
          @Override
          public void run() {
          FileDownloadThread[] fds = new FileDownloadThread[threadNum];
          try {
          URL url = new URL(urlStr);
          URLConnection conn = url.openConnection();
          //獲取下載文件的總大小
          fileSize = conn.getContentLength();
          //計算每個線程要下載的數據量
          blockSize = fileSize / threadNum;
          // 解決整除后百分比計算誤差
          downloadSizeMore = (fileSize % threadNum);
          File file = new File(fileName);
          for (int i = 0; i < threadNum; i++) {
          //啟動線程,分別下載自己需要下載的部分
          FileDownloadThread fdt = new FileDownloadThread(url, file,
          i * blockSize, (i + 1) * blockSize - 1);
          fdt.setName("Thread" + i);
          fdt.start();
          fds[i] = fdt;
          }
          boolean finished = false;
          while (!finished) {
          // 先把整除的余數搞定
          downloadedSize = downloadSizeMore;
          finished = true;
          for (int i = 0; i < fds.length; i++) {
          downloadedSize += fds[i].getDownloadSize();
          if (!fds[i].isFinished()) {
          finished = false;
          }
          }
          //通知handler去更新視圖組件
          handler.sendEmptyMessage(0);
          //休息1秒后再讀取下載進度
          sleep(1000);
          }
          } catch (Exception e) {
           
          }
           
          }
          }
          }

          程序中做了詳細的注釋,這里不再闡述。
          有問題請留言!

          posted on 2010-08-17 17:16 MEYE 閱讀(2368) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 南阳市| 云梦县| 隆化县| 柳河县| 岐山县| 马公市| 太原市| 仙桃市| 合山市| 阳春市| 三门峡市| 保康县| 尚志市| 固镇县| 丰镇市| 阿拉尔市| 桂林市| 桐乡市| 定襄县| 甘肃省| 周口市| 玉林市| 扎鲁特旗| 涪陵区| 永德县| 集贤县| 凤凰县| 房山区| 阜新市| 招远市| 汉寿县| 镇平县| 临高县| 定安县| 怀化市| 旺苍县| 怀宁县| 朔州市| 库车县| 确山县| 临安市|