Android 多線程斷點續傳同時下載多個大檔案

來源:互聯網
上載者:User

標籤:androi   toc   cut   讀取檔案   cti   skin   ide   ogre   列表   

最近學習在Android環境中一些網路請求方面的知識,其中有一部分是關於網路下載方面的知識。在這裡解析一下自己寫的demo,總結一下自己所學的知識。為demo的,仿照一些應用下載商城在ListView中列出附加元件,然後可以可以下載和停止。

1.概述

這裡有幾個比較重要的類DownloadManager、DownloadService、DownloadTask、ThreadDAOImpl。主要的下載流程如下。
(1) DownloadManager 負責下載任務的調配,以及下載服務DownloadService的啟動
(2) DownloadService 主擷取下載檔案的的一些資訊,包括檔案的名字、檔案的長度等,並建立下載任務DownloadTask
(3) DownloadTask 是正式下載檔案的類,首先查看資料庫裡有沒儲存過相應的斷點,並從相應的斷點開始下載,如果沒有則將檔案分段,並啟動下載
(4) ThreadDAOImpl 資料庫操作類,主要是儲存線程下載的斷點資訊

2.多線程斷點續傳

當然這裡最核心的部分就是多線程斷點續傳,原來不是很難,就是將要下載的檔案分割成多個部分,每個部分使用的不同的線程同時下載。

2.1擷取下載檔案長度,設定本地檔案

在DownloadService 設定下載檔案的資訊,如下一段代碼:

 class InitThread extends Thread {//        FileInfo fileInfo;        TaskInfo taskInfo;        public InitThread (TaskInfo taskInfo) {            this.taskInfo = taskInfo;        }        @Override        public void run() {            super.run();            Log.i(tag,"InitThread");            try {                URL url = new URL(taskInfo.getUrl());                HttpURLConnection con = (HttpURLConnection) url.openConnection();                con.setRequestMethod("GET");                con.setConnectTimeout(5000);                if(con.getResponseCode() ==  HttpURLConnection.HTTP_OK) {                    int len = con.getContentLength(); <span style="color:#ff0000;">//檔案的總長度</span>                    taskInfo.setLenght(len);                    if(len <= 0) {                        return;                    }                  …………此處省略部分                    //start 設定下載檔案                   <span style="color:#ff6666;"> RandomAccessFile accessFile = new RandomAccessFile(new File(taskInfo.getFilePath(),taskInfo.getFileName()),"rwd");                    accessFile.setLength(len); //設定檔案長度</span>                    accessFile.close();                    //end 設定下載檔案                …………此處省略部分                                   }            } catch (MalformedURLException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }        }    }

2.2 檔案分段

接下的工作是分段下載
舉個列子一個10M的檔案,分成三份求整10/3 = 3,前面的一二份分別是3M,最後一份是4M。所以第一份從0~2.9,第二份是從3~5.9,第三份是從6~10,這裡只是粗來的說明。接下來看代碼,在DownloadTask中有如下有如下代碼:

/** * 啟動下載 */public void downlaod() {     …………此處省略部分    //start 資料庫沒有對應的線程資訊,則建立相應的線程資訊    if(threadInfoList.size() <=0) {        <span style="color:#ff6666;">int block = mTaskInfo.getLenght()/mThreadCount; //將下載檔案分段,每段的長度</span>        if(block > 0) {            //start 根據線程數量分別建立線程資訊            for(int i = 0;i < mThreadCount;i++) {                ThreadInfo info = new ThreadInfo(i,mTaskInfo.getUrl(),i*block,(i+1)*block-1,0);                if(i == mThreadCount -1) {                   <span style="color:#ff0000;"> info.setEnd(mTaskInfo.getLenght()); //分段最後一個,結束位置到檔案總長度末尾</span>                }                threadInfoList.add(info);         //加入列表                mThreadDao.insertThread(info);   //向資料庫插入線程資訊            }            //end 根據線程數量分別建立線程資訊        }else {            ThreadInfo info = new ThreadInfo(0,mTaskInfo.getUrl(),0,mTaskInfo.getLenght(),0);            threadInfoList.add(info);            mThreadDao.insertThread(info);        }    }    //end 資料庫中沒有對應的線程資訊,則建立相應的線程資訊    …………此處省略部分}

2.3下載線程

下面是主要的下載檔案的線程

主要的是設定開始讀取和結束的地方:

con.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd()); //設定讀取檔案的位置,和結束位置

寫入本地檔案的地方:

accessFile.seek(start);    //設定開始寫入的位置
/**     * 下載線程     */    class DownloadThread extends  Thread {        …………此處省略部分        @Override        public void run() {                …………此處省略部分                    int start = threadInfo.getStart()+threadInfo.getFinished(); //讀取檔案的位置                    //start 初始化下載連結                    …………此處省略部分                    
con.setRequestProperty("Range", "bytes=" + start + "-" + threadInfo.getEnd()); //設定讀取檔案的位置,和結束位置                    //end 初始化下載連結                    //start 初始化下載到本地的檔案                    <span style="color:#ff0000;">accessFile  = new RandomAccessFile(new File(mTaskInfo.getFilePath(), mTaskInfo.getFileName()),"rwd");                    accessFile.seek(start);    //設定開始寫入的位置</span>                    //end 初始化下載到本地的檔案                   …………此處省略部分                        while((readLen = inputStream.read(buffer))!=-1) {                          <span style="background-color: rgb(255, 255, 255);"><span style="color:#ff0000;">  accessFile.write(buffer, 0, readLen);</span></span>//                            Log.i(tag, "readLen = " + readLen);                            finished += readLen;                            threadInfo.setFinished(finished);    //設定已經下載進度                            if(System.currentTimeMillis() - time >2000) {//                                Log.i(tag, "readLen = " + readLen);                                notifyProgress(threadInfo.getId(), finished); //每隔2秒通知下載進度                                time = System.currentTimeMillis();                            }                            //start 停止下載,儲存進度                            if(isPause) {                                Log.i(tag,"pause name = "+mTaskInfo.getFileName());                                notifyProgress(threadInfo.getId(), finished);        //通知下載進度                                mThreadDao.updateThread(threadInfo.getUrl(),threadInfo.getId(),finished);  //更新資料庫對應的線程資訊                                return;                            }                            //end 停止下載,儲存進度                        }                        //end 讀取輸入資料流寫入檔案                 …………此處省略部分                    }                } catch (MalformedURLException e) {                    e.printStackTrace();                } catch (ProtocolException e) {                    e.printStackTrace();                } catch (IOException e) {                    e.printStackTrace();                }finally {                         …………此處省略部分                }            super.run();        }    } 

2.4儲存斷點

在上面的DownloadThread下載線程中儲存斷點資訊,是使用資料庫形式儲存的。

mThreadDao.updateThread(threadInfo.getUrl(),threadInfo.getId(),finished);  //更新資料庫對應的線程資訊

3其他輔助類

(1) 資料庫操作類ThreadDAOImpl,斷點資訊的增、改、查、刪。
(2) 回調介面OnDownload,下載進度以及下載完成
(3) 下載任務資訊TaskInfo
(4) 線程資訊ThreadInfo

4線程池

由於使用到多線程同時下載,這裡在使用了線程池管理。在DownloadService類中建立並初始化線程池,按照CPU核心數量乘以2再加1設定線程池中線程的數量
mThreadPool = Executors.newFixedThreadPool(getNumberOfCPUCores()*2+1);  //初始化線程
在下載時使用三個線程同時下載
DownloadTask task = new DownloadTask(DownloadService.this,info,mThreadPool,3); //建立下載任務,3個線程同時下載

由於線程池內的線程數量是有限的,當啟動下載之後有閒置線程會馬上執行,如果沒有就只能等待下載任務完成再下載。

 

Android 多線程斷點續傳同時下載多個大檔案

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.