The general idea of multi-thread download is to implement file segmentation through the range attribute, and then use randomaccessfile to read and write the file, and finally merge it into a file.
First, let's take a look.
Create a project threaddemo
First, layout file threaddemo. xml
<? XML version = "1.0" encoding = "UTF-8"?> <Br/> <linearlayout xmlns: Android = "http://schemas.android.com/apk/res/android" <br/> Android: Orientation = "vertical" <br/> Android: layout_width = "fill_parent" <br/> Android: layout_height = "fill_parent" <br/> <textview <br/> Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" <br/> Android: TEXT = "" <br/> <textview <br/> Android: Id = "@ + ID/DownLoadURL" <br/> Android: l Ayout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" <br/> Android: lines = "5" <br/> <textview <br/> Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" <br/> Android: text = "Number of Threads" <br/> <edittext <br/> Android: id = "@ + ID/downloadnum" <br/> Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" <br/> <progressbar <br/> and Roid: Id = "@ + ID/downloadprogressbar" <br/> Android: layout_width = "fill_parent" <br/> style = "? Android: ATTR/progressbarstylehorizontal "<br/> Android: layout_height =" wrap_content "<br/> <textview <br/> Android: id = "@ + ID/downloadinfo" <br/> Android: layout_width = "fill_parent" <br/> Android: layout_height = "wrap_content" <br/> Android: TEXT = "download progress 0" <br/> <button <br/> Android: Id = "@ + ID/downloadbutton" <br/> Android: layout_width = "wrap_content" <br/> Android: layout_height = "wrap_content" <br/> Android: TEXT = "Start download" <br/> </linearlayout> <br/>
Main Interface acitivity
Public class threaddownloaddemo extends activity {</P> <p> private textview DownLoadURL; <br/> private edittext downloadnum; <br/> private button downloadbutton; <br/> private progressbar downloadprogressbar; <br/> private textview downloadinfo; <br/> private int downloadedsize = 0; <br/> private int filesize = 0; </P> <p> private long downloadtime; </P> <p> @ override <br/> Public void oncreate (bundle savedinstan Cestate) {<br/> super. oncreate (savedinstancestate); <br/> setcontentview (R. layout. threaddemo); </P> <p> DownLoadURL = (textview) findviewbyid (R. id. downLoadURL); <br/> DownLoadURL. settext ("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3"); <br/> downloadnum = (edittext) findviewbyid (R. id. downloadnum); <br/> downloadinfo = (textv Iew) findviewbyid (R. id. downloadinfo); <br/> downloadbutton = (button) findviewbyid (R. id. downloadbutton); <br/> downloadprogressbar = (progressbar) findviewbyid (R. id. downloadprogressbar); <br/> downloadprogressbar. setvisibility (view. visible); <br/> downloadprogressbar. setmax (100); <br/> downloadprogressbar. setprogress (0); <br/> downloadbutton. setonclicklistener (New onclicklistener () {<br/> Public void on Click (view v) {<br/> download (); <br/> downloadtime = systemclock. currentthreadtimemillis (); <br/>}< br/>}); <br/>}</P> <p> private void download () {<br/> // obtain the SD card directory <br/> string dowloaddir = environment. getexternalstoragedirectory () <br/> + "/threaddemodownload/"; <br/> file = new file (dowloaddir ); <br/> // create a download directory <br/> If (! File. exists () {<br/> file. mkdirs (); <br/>}</P> <p> // Number of reading and downloading threads. If it is null, a single thread is downloaded. <br/> int downloadtn = integer. valueof ("". equals (downloadnum. gettext () <br/>. tostring ())? "1": downloadnum. gettext (). tostring (); <br/> string filename = "hetang.mp3"; <br/> // set the Download button to unavailable before starting the download <br/> downloadbutton. setclickable (false); <br/> // progress bar is set to 0 <br/> downloadprogressbar. setprogress (0); <br/> // start the File Download thread <br/> New downloadtask ("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", integer <br/>. valueof (downloadtn ), Dowloaddir + filename ). start (); <br/>}</P> <p> handler = new handler () {<br/> @ override <br/> Public void handlemessage (Message MSG) {<br/> // when receiving the update view message, calculate the percentage of download completed, update the progress bar information at the same time <br/> int progress = (double. valueof (downloadedsize * 1.0/filesize * 100 ))). intvalue (); <br/> If (Progress = 100) {<br/> downloadbutton. setclickable (true); <br/> downloadinfo. settext ("Download complete! "); <Br/> dialog mdialog = new alertdialog. builder (threaddownloaddemo. this) <br/>. settitle ("prompt message") <br/>. setmessage ("download completed, total time:" + (systemclock. currentthreadtimemillis ()-downloadtime) + "millisecond") <br/>. setnegativebutton ("OK", new dialoginterface. onclicklistener () {<br/> @ override <br/> Public void onclick (dialoginterface dialog, int which) {<br/> dialog. dismiss (); <br/>}< br/>}) <br/>. create (); <br/> mdialog. s How (); <br/>}else {<br/> downloadinfo. settext ("current progress:" + progress + "%"); <br/>}< br/> downloadprogressbar. setprogress (Progress); <br/>}</P> <p >}; </P> <p> public class downloadtask extends thread {<br/> private int blocksize, downloadsizemore; <br/> private int threadnum = 5; <br/> string urlstr, threadno, filename; </P> <p> Public downloadtask (string urlstr, int threadnum, string filename) {<br/> This. URL STR = urlstr; <br/> This. threadnum = threadnum; <br/> This. filename = filename; <br/>}</P> <p> @ override <br/> Public void run () {<br/> filedownloadthread [] FDS = new filedownloadthread [threadnum]; <br/> try {<br/> URL url = new URL (urlstr ); <br/> urlconnection conn = URL. openconnection (); <br/> // prevents return-1 <br/> inputstream in = Conn. getinputstream (); <br/> // obtain the total size of the downloaded file <br/> filesize = Conn. getcontentlength (); <Br/> log. I ("BB", "=========================== filesize:" + filesize ); <br/> // calculate the volume of data to be downloaded by each thread <br/> blocksize = filesize/threadnum; <br/> // solves the percentage calculation error after Division <br/> downloadsizemore = (filesize % threadnum); <br/> file = new file (filename ); <br/> for (INT I = 0; I <threadnum; I ++) {<br/> log. I ("BB", "============================ I:" + I ); <br/> // start the thread to download the part you want to download <br/> filedownloadthread FDT = new filedownloadthread (URL, file, I * blocksize, (I + 1) * blocksize-1); <br/> FDT. setname ("Thread" + I); <br/> FDT. start (); <br/> FDS [I] = FDT; <br/>}< br/> Boolean finished = false; <br/> while (! Finished) {<br/> // get the remainder of the entire Division first <br/> downloadedsize = downloadsizemore; <br/> finished = true; <br/> for (INT I = 0; I <FDS. length; I ++) {<br/> downloadedsize + = FDS [I]. getdownloadsize (); <br/> If (! FDS [I]. isfinished () {<br/> finished = false; <br/>}< br/> handler. sendemptymessage (0); <br/> // thread paused for one second <br/> sleep (1000); <br/>}< br/>} catch (exception E) {<br/> E. printstacktrace (); <br/>}</P> <p >}< br/>}
Here, the startup thread divides the file into several parts, and each part starts another thread to download data.
File Download thread
Public class filedownloadthread extends thread {<br/> Private Static final int buffer_size = 1024; <br/> Private URL; <br/> private file; <br/> private int startposition; <br/> private int endposition; <br/> private int curposition; <br/> // identify whether the current thread has been downloaded <br/> private Boolean finished = false; <br/> private int downloadsize = 0; <br/> Public filedownloadthread (URL, file, int startposition, int endposition) {<br/> This. url = URL; <br/> This. file = file; <br/> This. startposition = startposition; <br/> This. curposition = startposition; <br/> This. endposition = endposition; <br/>}< br/> @ override <br/> Public void run () {<br/> bufferedinputstream Bis = NULL; <br/> randomaccessfile Fos = NULL; <br/> byte [] Buf = new byte [buffer_size]; <br/> urlconnection con = NULL; <br/> try {<br/> con = URL. openconnection (); <br/> con. setallowuserinteraction (true); <br/> // set the start and end points of the current thread download <br/> con. setrequestproperty ("range", "bytes =" + startposition + "-" + endposition); <br/> log. I ("BB", thread. currentthread (). getname () + "bytes =" + startposition + "-" + endposition ); <br/> // use randomaccessfile in Java to perform random read/write operations on the file <br/> Fos = new randomaccessfile (file, "RW "); <br/> // set the start position of the file to be written <br/> FOS. seek (startposition); <br/> Bis = new bufferedinputstream (con. getinputstream (); <br/> // The start loop reads and writes files in the form of a stream <br/> while (curposition <endposition) {<br/> int Len = bis. read (BUF, 0, buffer_size); <br/> If (LEN =-1) {<br/> break; <br/>}< br/> FOS. write (BUF, 0, Len); <br/> curposition = curposition + Len; <br/> If (curposition> endposition) {<br/> downloadsize + = len-(curposition-endposition) + 1; <br/>}else {<br/> downloadsize + = Len; <br/>}< br/> // set download to true <br/> This. finished = true; <br/> bis. close (); <br/> FOS. close (); <br/>}catch (ioexception e) {<br/> E. printstacktrace (); <br/>}</P> <p> Public Boolean isfinished () {<br/> return finished; <br/>}</P> <p> Public int getdownloadsize () {<br/> return downloadsize; <br/>}< br/>}
Here, the randomaccessfile seek method is used to locate the corresponding location and record the download volume in real time.
Of course, you need to add the corresponding permissions to connect to the Internet and access the SD card.
<Uses-Permission Android: Name = "android. permission. internet "/> <br/> <uses-Permission Android: Name =" android. permission. write_external_storage "> </uses-Permission>
So that we can see the problem of resumable upload. To be tested ~~