Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android實現多線程下載文件的方法

Android實現多線程下載文件的方法

編輯:關於Android編程

本文實例講述了Android實現多線程下載文件的方法。分享給大家供大家參考。具體如下:

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

首先看下效果圖:

創建工程 ThreadDemo

首先布局文件 threaddemo.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:orientation="vertical" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  > 
<TextView  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:text="下載地址" 
  /> 
<TextView 
  android:id="@+id/downloadurl" 
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:lines="5" 
  /> 
<TextView  
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:text="線程數" 
  /> 
<EditText 
  android:id="@+id/downloadnum" 
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  /> 
<ProgressBar 
  android:id="@+id/downloadProgressBar" 
  android:layout_width="fill_parent"  
   
  android:layout_height="wrap_content"  
  /> 
<TextView 
  android:id="@+id/downloadinfo" 
  android:layout_width="fill_parent"  
  android:layout_height="wrap_content"  
  android:text="下載進度 0" 
  /> 
<Button 
  android:id="@+id/downloadbutton" 
  android:layout_width="wrap_content"  
  android:layout_height="wrap_content"  
  android:text="開始下載" 
  /> 
</LinearLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:orientation="vertical" android:layout_width="fill_parent"  android:layout_height="fill_parent"  >
<TextView   android:layout_width="fill_parent"   android:layout_height="wrap_content" android:text="下載地址"  />
<TextViewandroid:id="@+id/downloadurl"android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="5"/>
<TextView   android:layout_width="fill_parent"   android:layout_height="wrap_content" android:text="線程數"  />
<EditTextandroid:id="@+id/downloadnum"android:layout_width="fill_parent" android:layout_height="wrap_content" />
<ProgressBarandroid:id="@+id/downloadProgressBar"android:layout_width="fill_parent"   android:layout_height="wrap_content" />
<TextViewandroid:id="@+id/downloadinfo"android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下載進度 0"/>
<Buttonandroid:id="@+id/downloadbutton"android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="開始下載"/>
</LinearLayout> 

主界面 Acitivity

public class ThreadDownloadDemo extends Activity { 
  private TextView downloadurl; 
  private EditText downloadnum; 
  private Button downloadbutton; 
  private ProgressBar downloadProgressBar; 
  private TextView downloadinfo; 
  private int downloadedSize = 0; 
  private int fileSize = 0; 
  private long downloadtime; 
  @Override 
  public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.threaddemo); 
    downloadurl = (TextView) findViewById(R.id.downloadurl); 
    downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3"); 
    downloadnum = (EditText) findViewById(R.id.downloadnum); 
    downloadinfo = (TextView) findViewById(R.id.downloadinfo); 
    downloadbutton = (Button) findViewById(R.id.downloadbutton); 
    downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar); 
    downloadProgressBar.setVisibility(View.VISIBLE); 
    downloadProgressBar.setMax(100); 
    downloadProgressBar.setProgress(0); 
    downloadbutton.setOnClickListener(new OnClickListener() { 
      public void onClick(View v) { 
        download(); 
        downloadtime = SystemClock.currentThreadTimeMillis(); 
      } 
    }); 
  } 
  private void download() { 
    // 獲取SD卡目錄  
    String dowloadDir = Environment.getExternalStorageDirectory() 
        + "/threaddemodownload/"; 
    File file = new File(dowloadDir); 
    //創建下載目錄  
    if (!file.exists()) { 
      file.mkdirs(); 
    } 
    //讀取下載線程數,如果為空,則單線程下載  
    int downloadTN = Integer.valueOf("".equals(downloadnum.getText() 
        .toString()) ? "1" : downloadnum.getText().toString()); 
    String fileName = "hetang.mp3"; 
    //開始下載前把下載按鈕設置為不可用  
    downloadbutton.setClickable(false); 
    //進度條設為0  
    downloadProgressBar.setProgress(0); 
    //啟動文件下載線程  
    new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", 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) { 
        downloadbutton.setClickable(true); 
        downloadinfo.setText("下載完成!"); 
        Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this) 
          .setTitle("提示信息") 
          .setMessage("下載完成,總用時為:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒") 
          .setNegativeButton("確定", new DialogInterface.OnClickListener(){ 
            @Override 
            public void onClick(DialogInterface dialog, int which) { 
              dialog.dismiss(); 
            } 
          }) 
          .create(); 
        mdialog.show(); 
      } else { 
        downloadinfo.setText("當前進度:" + progress + "%"); 
      } 
      downloadProgressBar.setProgress(progress); 
    } 
  }; 
  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(); 
        //防止返回-1  
        InputStream in = conn.getInputStream(); 
        //獲取下載文件的總大小  
        fileSize = conn.getContentLength(); 
        Log.i("bb", "======================fileSize:"+fileSize); 
        //計算每個線程要下載的數據量  
        blockSize = fileSize / threadNum; 
        // 解決整除後百分比計算誤差  
        downloadSizeMore = (fileSize % threadNum); 
        File file = new File(fileName); 
        for (int i = 0; i < threadNum; i++) { 
          Log.i("bb", "======================i:"+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.sendEmptyMessage(0); 
          //線程暫停一秒  
          sleep(1000); 
        } 
      } catch (Exception e) { 
        e.printStackTrace(); 
      } 
    } 
  } 
} 
public class ThreadDownloadDemo extends Activity {
private TextView downloadurl;
private EditText downloadnum;
private Button downloadbutton;
private ProgressBar downloadProgressBar;
private TextView downloadinfo;
private int downloadedSize = 0;
private int fileSize = 0;
private long downloadtime;
@Overridepublic void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.threaddemo);
downloadurl = (TextView) findViewById(R.id.downloadurl);
downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3");
downloadnum = (EditText) findViewById(R.id.downloadnum);
downloadinfo = (TextView) findViewById(R.id.downloadinfo);
downloadbutton = (Button) findViewById(R.id.downloadbutton);
downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);
downloadProgressBar.setVisibility(View.VISIBLE);
downloadProgressBar.setMax(100);
downloadProgressBar.setProgress(0);
downloadbutton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {download();
downloadtime = SystemClock.currentThreadTimeMillis();
}
}
);
}
private void download() {// 獲取SD卡目錄
String dowloadDir = Environment.getExternalStorageDirectory()+ "/threaddemodownload/";
File file = new File(dowloadDir);
//創建下載目錄
if (!file.exists()) {file.mkdirs();
}//讀取下載線程數,如果為空,則單線程下載
int downloadTN = Integer.valueOf("".equals(downloadnum.getText().toString()) ? "1" : downloadnum.getText().toString());
String fileName = "hetang.mp3";
//開始下載前把下載按鈕設置為不可用
downloadbutton.setClickable(false);
//進度條設為0
downloadProgressBar.setProgress(0);
//啟動文件下載線程
new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", Integer.valueOf(downloadTN), dowloadDir + fileName).start();
}
Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {
//當收到更新視圖消息時,計算已完成下載百分比,同時更新進度條信息
int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();
if (progress == 100) {downloadbutton.setClickable(true);
downloadinfo.setText("下載完成!");
Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this).setTitle("提示信息").setMessage("下載完成,總用時為:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒").setNegativeButton("確定", new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();
}}).create();
mdialog.show();
} else {
downloadinfo.setText("當前進度:" + progress + "%");
}
downloadProgressBar.setProgress(progress);
}
}; 
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;
}
@Overridepublic void run() {
FileDownloadThread[] fds = new FileDownloadThread[threadNum];
try {URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
//防止返回-1
InputStream in = conn.getInputStream();
//獲取下載文件的總大小
fileSize = conn.getContentLength();
Log.i("bb", "======================fileSize:"+fileSize);
//計算每個線程要下載的數據量
blockSize = fileSize / threadNum;
// 解決整除後百分比計算誤差
downloadSizeMore = (fileSize % threadNum);
File file = new File(fileName);
for (int i = 0; i < threadNum; i++) {
Log.i("bb", "======================i:"+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.sendEmptyMessage(0);
//線程暫停一秒sleep(1000);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
} 

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

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); 
      Log.i("bb", Thread.currentThread().getName()+" 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) { 
      e.printStackTrace(); 
    } 
  } 
  public boolean isFinished(){ 
    return finished; 
  } 
  public int getDownloadSize() { 
    return downloadSize; 
  } 
} 
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;
}
@Overridepublic 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);
Log.i("bb", Thread.currentThread().getName()+" 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) {
e.printStackTrace();
}
}
public boolean isFinished(){return finished;}
public int getDownloadSize() {return downloadSize;}
}

這裡通過RandomAccessFile 的seek方法定位到相應的位置 並實時記錄下載量
當然這裡需要聯網和訪問SD卡 所以要加上相應的權限

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

這樣就OK了 下面可以看看斷點續傳的問題了。有待測試~~

希望本文所述對大家的Android程序設計有所幫助。

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