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

Android實現網絡多線程文件下載

編輯:關於Android編程

實現原理

(1)首先獲得下載文件的長度,然後設置本地文件的長度。

(2)根據文件長度和線程數計算每條線程下載的數據長度和下載位置。

如:文件的長度為6M,線程數為3,那麼,每條線程下載的數據長度為2M,每條線程開始下載的位置如下圖所示:

(網上找的圖)

例如10M大小,使用3個線程來下載,

線程下載的數據長度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2個線程下載長度是4M,第三個線程下載長度為2M

下載開始位置:線程id*每條線程下載的數據長度 = ?

下載結束位置:(線程id+1)*每條線程下載的數據長度-1=?

之前練習時的一個demo,不多說了,直接上代碼吧,有關斷點續傳,需要使用數據庫,不再加了,網上有很多成熟的項目可以直接用。

實例

MainApp:

package com.amos.app; 
import java.io.File; 
import java.io.IOException; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.net.URLConnection; 
import com.amos.download.R; 
import android.annotation.SuppressLint; 
import android.app.Activity; 
import android.os.Bundle; 
import android.os.Environment; 
import android.os.Handler; 
import android.os.Message; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.ProgressBar; 
import android.widget.TextView; 
import android.widget.Toast; 
/** 
* @author yangxiaolong 
* @2014-5-6 
*/ 
public class MainApp extends Activity implements OnClickListener { 
private static final String TAG = MainApp.class.getSimpleName(); 
/** 顯示下載進度TextView */ 
private TextView mMessageView; 
/** 顯示下載進度ProgressBar */ 
private ProgressBar mProgressbar; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.progress_activity); 
findViewById(R.id.download_btn).setOnClickListener(this); 
mMessageView = (TextView) findViewById(R.id.download_message); 
mProgressbar = (ProgressBar) findViewById(R.id.download_progress); 
} 
@Override 
public void onClick(View v) { 
if (v.getId() == R.id.download_btn) { 
doDownload(); 
} 
} 
/** 
* 使用Handler更新UI界面信息 
*/ 
@SuppressLint("HandlerLeak") 
Handler mHandler = new Handler() { 
@Override 
public void handleMessage(Message msg) { 
mProgressbar.setProgress(msg.getData().getInt("size")); 
float temp = (float) mProgressbar.getProgress() 
/ (float) mProgressbar.getMax(); 
int progress = (int) (temp * 100); 
if (progress == 100) { 
Toast.makeText(MainApp.this, "下載完成!", Toast.LENGTH_LONG).show(); 
} 
mMessageView.setText("下載進度:" + progress + " %"); 
} 
}; 
/** 
* 下載准備工作,獲取SD卡路徑、開啟線程 
*/ 
private void doDownload() { 
// 獲取SD卡路徑 
String path = Environment.getExternalStorageDirectory() 
+ "/amosdownload/"; 
File file = new File(path); 
// 如果SD卡目錄不存在創建 
if (!file.exists()) { 
file.mkdir(); 
} 
// 設置progressBar初始化 
mProgressbar.setProgress(0); 
// 簡單起見,我先把URL和文件名稱寫死,其實這些都可以通過HttpHeader獲取到 
String downloadUrl = "http://gdown.baidu.com/data/wisegame/91319a5a1dfae322/baidu_16785426.apk"; 
String fileName = "baidu_16785426.apk"; 
int threadNum = 5; 
String filepath = path + fileName; 
Log.d(TAG, "download file path:" + filepath); 
downloadTask task = new downloadTask(downloadUrl, threadNum, filepath); 
task.start(); 
} 
/** 
* 多線程文件下載 
* 
* @author yangxiaolong 
* @2014-8-7 
*/ 
class downloadTask extends Thread { 
private String downloadUrl;// 下載鏈接地址 
private int threadNum;// 開啟的線程數 
private String filePath;// 保存文件路徑地址 
private int blockSize;// 每一個線程的下載量 
public downloadTask(String downloadUrl, int threadNum, String fileptah) { 
this.downloadUrl = downloadUrl; 
this.threadNum = threadNum; 
this.filePath = fileptah; 
} 
@Override 
public void run() { 
FileDownloadThread[] threads = new FileDownloadThread[threadNum]; 
try { 
URL url = new URL(downloadUrl); 
Log.d(TAG, "download file http path:" + downloadUrl); 
URLConnection conn = url.openConnection(); 
// 讀取下載文件總大小 
int fileSize = conn.getContentLength(); 
if (fileSize <= 0) { 
System.out.println("讀取文件失敗"); 
return; 
} 
// 設置ProgressBar最大的長度為文件Size 
mProgressbar.setMax(fileSize); 
// 計算每條線程下載的數據長度 
blockSize = (fileSize % threadNum) == 0 ? fileSize / threadNum 
: fileSize / threadNum + 1; 
Log.d(TAG, "fileSize:" + fileSize + " blockSize:"); 
File file = new File(filePath); 
for (int i = 0; i < threads.length; i++) { 
// 啟動線程,分別下載每個線程需要下載的部分 
threads[i] = new FileDownloadThread(url, file, blockSize, 
(i + 1)); 
threads[i].setName("Thread:" + i); 
threads[i].start(); 
} 
boolean isfinished = false; 
int downloadedAllSize = 0; 
while (!isfinished) { 
isfinished = true; 
// 當前所有線程下載總量 
downloadedAllSize = 0; 
for (int i = 0; i < threads.length; i++) { 
downloadedAllSize += threads[i].getDownloadLength(); 
if (!threads[i].isCompleted()) { 
isfinished = false; 
} 
} 
// 通知handler去更新視圖組件 
Message msg = new Message(); 
msg.getData().putInt("size", downloadedAllSize); 
mHandler.sendMessage(msg); 
// Log.d(TAG, "current downloadSize:" + downloadedAllSize); 
Thread.sleep(1000);// 休息1秒後再讀取下載進度 
} 
Log.d(TAG, " all of downloadSize:" + downloadedAllSize); 
} catch (MalformedURLException e) { 
e.printStackTrace(); 
} catch (IOException e) { 
e.printStackTrace(); 
} catch (InterruptedException e) { 
e.printStackTrace(); 
} 
} 
} 
}

FileDownloadThread:

package com.amos.app; 
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; 
/** 
* 文件下載類 
* 
* @author yangxiaolong 
* @2014-5-6 
*/ 
public class FileDownloadThread extends Thread { 
private static final String TAG = FileDownloadThread.class.getSimpleName(); 
/** 當前下載是否完成 */ 
private boolean isCompleted = false; 
/** 當前下載文件長度 */ 
private int downloadLength = 0; 
/** 文件保存路徑 */ 
private File file; 
/** 文件下載路徑 */ 
private URL downloadUrl; 
/** 當前下載線程ID */ 
private int threadId; 
/** 線程下載數據長度 */ 
private int blockSize; 
/** 
* 
* @param url:文件下載地址 
* @param file:文件保存路徑 
* @param blocksize:下載數據長度 
* @param threadId:線程ID 
*/ 
public FileDownloadThread(URL downloadUrl, File file, int blocksize, 
int threadId) { 
this.downloadUrl = downloadUrl; 
this.file = file; 
this.threadId = threadId; 
this.blockSize = blocksize; 
} 
@Override 
public void run() { 
BufferedInputStream bis = null; 
RandomAccessFile raf = null; 
try { 
URLConnection conn = downloadUrl.openConnection(); 
conn.setAllowUserInteraction(true); 
int startPos = blockSize * (threadId - 1);//開始位置 
int endPos = blockSize * threadId - 1;//結束位置 
//設置當前線程下載的起點、終點 
conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); 
System.out.println(Thread.currentThread().getName() + " bytes=" 
+ startPos + "-" + endPos); 
byte[] buffer = new byte[1024]; 
bis = new BufferedInputStream(conn.getInputStream()); 
raf = new RandomAccessFile(file, "rwd"); 
raf.seek(startPos); 
int len; 
while ((len = bis.read(buffer, 0, 1024)) != -1) { 
raf.write(buffer, 0, len); 
downloadLength += len; 
} 
isCompleted = true; 
Log.d(TAG, "current thread task has finished,all size:" 
+ downloadLength); 
} catch (IOException e) { 
e.printStackTrace(); 
} finally { 
if (bis != null) { 
try { 
bis.close(); 
} catch (IOException e) { 
e.printStackTrace(); 
} 
} 
if (raf != null) { 
try { 
raf.close(); 
} catch (IOException e) { 
e.printStackTrace(); 
} 
} 
} 
} 
/** 
* 線程文件是否下載完畢 
*/ 
public boolean isCompleted() { 
return isCompleted; 
} 
/** 
* 線程下載文件長度 
*/ 
public int getDownloadLength() { 
return downloadLength; 
} 
}

效果圖:


Log控制台:

可以看到文件總大小、我們創建的5個線程每個負責下載的區間

SD卡:

關於Android實現網絡多線程文件下載小編就給大家介紹這麼多,希望對大家有所幫助!同時也非常感謝大家一直以來對本站網站的支持!

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