Android-multi-thread download process analysis
The process of multi-threaded File Download is as follows:
(1) first obtain the length of the downloaded file, and then set the length of the local file.
HttpURLConnection. getContentLength (); // obtain the length of the downloaded object
RandomAccessFile file = new RandomAccessFile ("QQSetup.exe", "rwd ");
File. setLength (filesize); // you can specify the length of a local file.
(2) Calculate the length and location of Data downloaded by each thread Based on the file length and thread count.
For example, if the file length is 6 MB and the number of threads is 3, the data downloaded by each thread is 2 MB, as shown in.
For example, the size is 10 MB and three threads are used for download,
The Data Length downloaded by the thread (10% 3 = 0? 10/3: 10/3 + 1). The download length of the 1st thread is 4 MB, and the download length of the third thread is 2 MB.
Download start position: thread id * length of data downloaded by each thread =?
Download end position: (thread id + 1) * length of data downloaded by each thread-1 =?
(3) use the Range header field of Http to specify the position where each thread starts to download files and where to download files,
For example, the file is downloaded from 2 MB to 4M-1byte.
The Code is as follows: HttpURLConnection. setRequestProperty ("Range", "bytes = 2097152-4194303 ");
(4) save the file and use the RandomAccessFile class to specify where each thread starts to write data from the local file.
RandomAccessFilethreadfile = newRandomAccessFile ("QQWubiSetup.exe", "rwd ");
Threadfile. seek (2097152); // from where the file is written
/*** Multi-Thread download, UI update class * @ author young **/public class MultiThreadDownload extends Thread {private static final String TAG = "MultiThreadDownload "; /** the size of each thread to be downloaded */private int blockSize;/the default number of *** threads is 5. */private int threadNum = 5; /***** file size */private int fileSize;/***** File url, thread number, file name */private String UrlStr, ThreadNo, fileName;/*** saved path */private String SavePath;/** download percentage */private int downloadPercent = 0;/** average download speed */private int downloadSpeed = 0; /** download time */private int usedTime = 0;/** current time */private long curTime; /** whether the download has been completed */private boolean completed = false; private Handler handler; /*** download constructor * @ param url request the download URL * @ param handler UI update the path to save the file using * @ param savePath */public MultiThreadDownload (Handler handler, string url, String saveP Ath) {this. handler = handler; this. urlStr = url; this. savePath = savePath; Log. e (TAG, toString () ;}@ Override public void run () {FileDownloadThread [] fds = new FileDownloadThread [threadNum]; // set the number of threads. try {URL url = new URL (UrlStr); URLConnection conn = url. openConnection (); fileSize = conn. getContentLength (); this. fileName = FileUtil. getFileName (UrlStr); // create only one File, saveFile download content File saveFile = n Ew File (savePath + "/" + fileName); Log. e (TAG, "file Total:" + fileSize + "savePath" + savePath + "fileName" + fileName); RandomAccessFile accessFile = new RandomAccessFile (saveFile, "rwd "); // set the length of the local file to be the same as that of the downloaded file. setLength (fileSize); accessFile. close (); // Handler updates the UI and sends the message sendMsg (FileUtil. startDownloadMeg); // blockSize = (fileSize % threadNum) = 0) of data downloaded by each thread )? (FileSize/threadNum) :( fileSize/threadNum + 1); Log. e (TAG, "download each thread separately:" + 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;}/*** get the data and update the UI until all download threads have downloaded the data. */Boolean finished = false; // the start time, which is placed out of the loop. usedTime is the total time 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 ); /* refresh the interface once every second */sendMsg (FileUtil. updateDownloadMeg);} Log. e (TAG, "download completed"); completed = true; sendMsg (FileUtil. endDownloadMeg);} catch (Exception e) {Log. e (TAG, "multi file error Exception" + e. getMessage (); e. printStackTrace ();} super. run ();}/*** get the file size * @ return */public int getFileSize () {return this. fileSize;}/*** get the downloaded quantity * @ return */public int getDownloadSize () {return this. downloadSize;}/*** get download percentage * @ return */public int getDownloadPercent () {return this. downloadPercent;}/*** get download speed * @ return */public int getDownloadSpeed () {return this. downloadSpeed;}/*** modify the default number of threads * @ param threadNum */public void setThreadNum (int threadNum) {this. threadNum = threadNum;}/*** mark of multipart download completion * @ return */public boolean isCompleted () {return this. completed ;}@ Override public String toString () {return "MultiThreadDownload [threadNum =" + threadNum + ", fileSize =" + fileSize + ", UrlStr =" + UrlStr + ", threadNo = "+ ThreadNo +", savePath = "+ savePath +"] ";}/*** send a message. The user prompts **/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";/** buffer */private static final int BUFF_SIZE = 1024; /** download URL */private URL;/** cached FIle */private File file;/** start position */private int startPosition; /** end position */private int endPosition;/** current position */private int curPosition;/** completed */private boolean finished = false; /** how many files have been downloaded */private int downloadSize = 0;/***** multipart file download, you can create a multi-threaded mode * @ param url to download the URL * @ param file to download the file * @ param startPosition start position * @ param endPosition end position */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); // set the timeout conn. setreadtimeouts (10000); conn. setAllowUserInteraction (true); System. out. println (this. getName () + "startPosition" + startPosition + "endPosition" + endPosition); conn. setRequestProperty ("Range", "bytes =" + (startPosition) + "-" + endPosition); // obtain the remaining undownloaded rAccessFile = new RandomAccessFile (file, "rwd"); // read/write // set the position where data is written. seek (startPosition); bis = new BufferedInputStream (conn. getInputStream (), BUFF_SIZE); while (curPosition
EndPosition) {// If the download is too large, the excess part of System. out. println ("curPosition> endPosition !!!! "); Int extraLen = curPosition-endPosition; downloadSize + = (len-extraLen + 1);} else {downloadSize + = len;} this. finished = true; // Log of download completion in the current phase. e (TAG, "current" + this. getName () + "download completed");} catch (Exception e) {Log. e (TAG, "download error Exception" + e. getMessage (); e. printStackTrace ();} finally {// disable stream FileUtil. closeInputStream (bis); try {rAccessFile. close ();} catch (IOException e) {// TODO Auto-generated catch block Log. e ("AccessFile", "AccessFile IOException" + e. getMessage () ;}} super. run ();}/*** whether the current segment download is complete * @ return */public boolean isFinished () {return finished ;} /*** number of downloads * @ return */public int getDownloadSize () {return downloadSize;} @ Override public String toString () {return "FileDownloadThread [url =" + url + ", file =" + file + ", startPosition =" + startPosition + ", endPosition =" + endPosition + ", curPosition = "+ curPosition +", finished = "+ finished +", downloadSize = "+ downloadSize +"] ";}
Multi-threaded download is a multipart download. When a file is created and saved, the sub-thread writes data through the RandomAccessFile class.
Sample source code: demo download