android 多線程下載 顯示進度 速度
https://blog.csdn.net/JianTao_Yang/article/details/8433905
功能要求:從網絡下載一APK應用,顯示下載速度、進度,並安裝應用。
運行效果圖:
工程結構圖:
很簡單,就一個activity,一個更新UI的線程,一個下載線程加個文件處理類
主要代碼:
- /**
- *多線程下載,UI更新類
- *@author young
- * */
- public class MultiThreadDownload extends Thread{
- private static final String TAG = "MultiThreadDownload";
- /**每一個線程需要下載的大小 */
- private int blockSize;
- /*** 線程數量<br> 默認為5個線程下載*/
- private int threadNum = 5;
- /*** 文件大小 */
- private int fileSize;
- /** * 已經下載多少 */
- private int downloadSize;
- /**文件的url,線程編號,文件名稱*/
- private String UrlStr,ThreadNo,fileName;
- /***保存的路徑*/
- private String savePath;
- /**下載的百分比*/
- private int downloadPercent = 0;
- /**下載的 平均速度*/
- private int downloadSpeed = 0;
- /**下載用的時間*/
- private int usedTime = 0;
- /**當前時間*/
- private long curTime;
- /**是否已經下載完成*/
- private boolean completed = false;
- private Handler handler ;
- /**
- * 下載的構造函數
- * @param url 請求下載的URL
- * @param handler UI更新使用
- * @param savePath 保存文件的路徑
- */
- public MultiThreadDownload(Handler handler,String url,String savePath)
- {
- this.handler = handler;
- this.UrlStr = url;
- this.savePath = savePath;
- Log.e(TAG, toString());
- }
- @Override
- public void run() {
- FileDownloadThread[] fds = new FileDownloadThread[threadNum];//設置線程數量
- try {
- URL url = new URL(UrlStr);
- URLConnection conn = url.openConnection();
- fileSize = conn.getContentLength();
- this.fileName = FileUtil.getFileName(UrlStr);
- //隻創建一個文件,saveFile下載內容
- File saveFile = new File(savePath+"/"+fileName);
- Log.e(TAG, "文件一共:"+fileSize+" savePath "+savePath+" fileName "+fileName);
- RandomAccessFile accessFile = new RandomAccessFile(saveFile,"rwd");
- //設置本地文件的長度和下載文件相同
- accessFile.setLength(fileSize);
- accessFile.close();
- //Handler更新UI,發送消息
- sendMsg(FileUtil.startDownloadMeg);
- //每塊線程下載數據
- blockSize = ((fileSize%threadNum)==0)?(fileSize/threadNum):(fileSize/threadNum+1);
- Log.e(TAG, "每個線程分別下載 :"+blockSize);
- for (int i = 0; i < threadNum; i++) {
- int curThreadEndPosition = (i+1)!=threadNum ? ((i+1)*blockSize-1) : fileSize;
- FileDownloadThread fdt = new FileDownloadThread(url, saveFile, i*blockSize, curThreadEndPosition);
- fdt.setName("thread"+i);
- fdt.start();
- fds[i]=fdt;
- }
- /**
- * 獲取數據,更新UI,直到所有下載線程都下載完成。
- */
- boolean finished = false;
- //開始時間,放在循環外,求解的usedTime就是總時間
- long startTime = System.currentTimeMillis();
- while(!finished)
- {
- downloadSize = 0;
- finished = true;
- for (int i = 0; i < fds.length; i++) {
- downloadSize+= fds[i].getDownloadSize();
- if(!fds[i].isFinished())
- {
- finished = false;
- }
- }
- downloadPercent = (downloadSize*100)/fileSize;
- curTime = System.currentTimeMillis();
- System.out.println("curTime = "+curTime+" downloadSize = "+downloadSize+" usedTime "+(int) ((curTime-startTime)/1000));
- usedTime = (int) ((curTime-startTime)/1000);
- if(usedTime==0)usedTime = 1;
- downloadSpeed = (downloadSize/usedTime)/1024;
- sleep(1000);/*1秒鍾刷新一次界麵*/
- sendMsg(FileUtil.updateDownloadMeg);
- }
- Log.e(TAG, "下載完成");
- completed = true;
- sendMsg(FileUtil.endDownloadMeg);
- } catch (Exception e) {
- Log.e(TAG, "multi file error Exception "+e.getMessage());
- e.printStackTrace();
- }
- super.run();
- }
- /**
- * 得到文件的大小
- * @return
- */
- public int getFileSize()
- {
- return this.fileSize;
- }
- /**
- * 得到已經下載的數量
- * @return
- */
- public int getDownloadSize()
- {
- return this.downloadSize;
- }
- /**
- * 獲取下載百分比
- * @return
- */
- public int getDownloadPercent(){
- return this.downloadPercent;
- }
- /**
- * 獲取下載速度
- * @return
- */
- public int getDownloadSpeed(){
- return this.downloadSpeed;
- }
- /**
- * 修改默認線程數
- * @param threadNum
- */
- public void setThreadNum(int threadNum){
- this.threadNum = threadNum;
- }
- /**
- * 分塊下載完成的標誌
- * @return
- */
- public boolean isCompleted(){
- return this.completed;
- }
- @Override
- public String toString() {
- return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize="
- + fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo
- + ", savePath=" + savePath + "]";
- }
- /**
- * 發送消息,用戶提示
- * */
- private void sendMsg(int what)
- {
- Message msg = new Message();
- msg.what = what;
- handler.sendMessage(msg);
- }
下載類:
- public class FileDownloadThread extends Thread{
- private static final String TAG = "FileDownloadThread";
- /**緩衝區 */
- private static final int BUFF_SIZE = 1024;
- /**需要下載的URL*/
- private URL url;
- /**緩存的FIle*/
- private File file;
- /**開始位置*/
- private int startPosition;
- /**結束位置*/
- private int endPosition;
- /**當前位置*/
- private int curPosition;
- /**完成*/
- private boolean finished = false;
- /**已經下載多少*/
- private int downloadSize = 0;
- /***
- * 分塊文件下載,可以創建多線程模式
- * @param url 下載的URL
- * @param file 下載的文件
- * @param startPosition 開始位置
- * @param endPosition 結束位置
- */
- 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;
- Log.e(TAG, toString());
- }
- @Override
- public void run() {
- BufferedInputStream bis = null;
- RandomAccessFile rAccessFile = null;
- byte[] buf = new byte[BUFF_SIZE];
- URLConnection conn = null;
- try {
- conn = url.openConnection();
- conn.setConnectTimeout(10000);//設置超時
- conn.setReadTimeout(10000);
- conn.setAllowUserInteraction(true);
- System.out.println(this.getName()+" startPosition "+startPosition+" endPosition "+endPosition);
- conn.setRequestProperty("Range", "bytes="+(startPosition)+"-"+endPosition); //取剩餘未下載的
- rAccessFile = new RandomAccessFile(file,"rwd");//讀寫
- //設置從什麼位置開始寫入數據
- rAccessFile.seek(startPosition);
- bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE);
- while(curPosition<endPosition) //當前位置小於結束位置 繼續下載
- {
- int len = bis.read(buf,0,BUFF_SIZE);
- if(len==-1) //下載完成
- {
- break;
- }
- rAccessFile.write(buf,0,len);
- curPosition = curPosition +len;
- if(curPosition > endPosition)
- { //如果下載多了,則減去多餘部分
- System.out.println(" curPosition > endPosition !!!!");
- int extraLen = curPosition-endPosition;
- downloadSize += (len-extraLen+1);
- }else{
- downloadSize+=len;
- }
- }
- this.finished = true; //當前階段下載完成
- Log.e(TAG, "當前"+this.getName()+"下載完成");
- } catch (Exception e) {
- Log.e(TAG, "download error Exception "+e.getMessage());
- e.printStackTrace();
- }finally{
- //關閉流
- FileUtil.closeInputStream(bis);
- try {
- rAccessFile.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- Log.e("AccessFile", "AccessFile IOException "+e.getMessage());
- }
- }
- super.run();
- }
- /**
- * 是否完成當前段下載完成
- * @return
- */
- public boolean isFinished() {
- return finished;
- }
- /**
- * 已經下載多少
- * @return
- */
- public int getDownloadSize() {
- return downloadSize;
- }
- @Override
- public String toString() {
- return "FileDownloadThread [url=" + url + ", margin:0px;padding:0px;border:none;background-color:inherit;"> + file
- + ", startPosition=" + startPosition + ", endPosition="
- + endPosition + ", curPosition=" + curPosition + ", finished="
- + finished + ", downloadSize=" + downloadSize + "]";
- }
這裏麵多線程下載是分段下載,創建保存一個文件(之前每個子線程都創建一個子文件,最後整合,發現文件整合有問題,安裝失敗,原因沒找到),子線程分別通過RandomAccessFile類進行寫入操作。
最後更新:2017-04-04 07:03:57