Android multi-thread resumable download-commercial-level code exposure

Source: Internet
Author: User

The landlord has been grinding the sword for three years (not a sword of course) and has devoted himself to the android multi-thread download demo. Some people ask "How to write or demo ?", Because I am too busy,
I wrote a little bit every day, and now I wrote a download device, which means the download management class is a complete module. This is enough for beginners to learn. No, It is enough.

This is not just a simple demo. It is definitely a commercial-level example that you have never seen before. It supports multi-thread download and resumable data transfer. It only uses WiFi network download to display the download speed and user-friendly prompts.
And powerful Fault Tolerance Mechanisms in one, absolutely practical, absolutely professional.

Of course, I wrote this to download the APK. You can change it to a more general download tool. The only disadvantage is that randomaccessfile is used on Android to create a large file.
The speed is slow, so the progress of the previous few seconds is 0. I wonder if anyone can help me solve this problem.

The key code is given below.

Package COM. h3C. downloadengine; import Java. io. file; import Java. io. ioexception; import Java. io. inputstream; import Java. io. randomaccessfile; import java.net. httpurlconnection; import java.net. URL; import Java. util. arraylist; import android. content. context; import android. OS. environment; import android. util. log; import COM. h3C. downloadengine. common. downloadererrorexception; import COM. h3C. downloadengine. common. Engineconstants; import COM. h3C. downloadengine. common. engineutil; import COM. h3C. downloadengine. common. enginevariable; import COM. h3C. downloadengine. DB. enginedboperator; import COM. h3C. downloadengine. entity. downloadbean; public class downloader {private final static string tag = "downloader"; private final static byte [] lock_getfilesize = new byte [1]; private final static byte [] lock_refresh_progress = New byte [1]; private int mthreadcount = 4; // The default number of subthreads is 4 private int buffersize = 1024*16; // 16 k a private downloadbean mbean; // note that the bean of dwonloader is not its subbean private context mcontext; private downloadenginecallback mcallback; private enginedboperator mdboper; private int mdonethreadcount = 0; // number of completed threads private int mstate = engineconstants. download_state_init; // The download server status private arraylist <down Loadbean> mbeans = new arraylist <downloadbean> (mthreadcount); Public downloader (downloadbean bean, context, downloadenginecallback callback) throws downloaderrorexception {This. mbean = bean; this. mcontext = context; this. mcallback = callback; this. mdboper = enginedboperator. getinstance (context); If (this. mdboper! = NULL) {If (this. mdboper. ishasdownloadtaskbyurl (bean. URL) {// if this task has been stored in the getdownloaderinfofromdb (bean);} else {// insert information to the database adddownloaderinfotodb (bean );}} else {callbackerror ("downloader error, probably because enginedboperator is null. "); throw new downloadererrorexception (" downloader error, probably because enginedboperator is null. ") ;}} public downloadbean getdownloaderinfo () {return mbean;} public int getdownloaderstate (){ Return mstate;}/*** request initialization ** @ Param state */protected void setdownloaderstate (INT state) {mstate = State; If (State = engineconstants. download_state_init) {mbean. currentposition = 0 ;}/ *** Add the download information to the database. This method is used to initialize Downloader, when this task does not exist in the Database, ** @ Param bean * @ throws downloadererrorexception */private void adddownloaderinfotodb (downloadbean bean) throws downloaderrorexception {If (mstat E! = Engineconstants. download_state_init & mstate! = Engineconstants. download_state_stop & mstate! = Engineconstants. download_state_error) {callbackerror ("this task has been added to the database"); throw new downloaderrorexception ("this task has been added to the database");} If (mdboper! = NULL) {long filesize = bean. filesize; If (mbeans. size ()> 0) {mbeans. clear () ;}try {If (filesize> 0) {// determine the input filesize. If it is greater than 0, you do not need to obtain it from the network, directly initialize n sub-downloads if (! Hasspaceinsdcard () {return;} long range = filesize/mthreadcount; // file segment value for (INT I = 0; I <mthreadcount-1; I ++) {downloadbean subbean = (downloadbean) bean. clone (); subbean. threadid = I; subbean. startposition = I * range; subbean. endposition = (I + 1) * Range-1; mbeans. add (subbean);} downloadbean subbean = (downloadbean) bean. clone (); subbean. threadid = mthreadcount-1; subbean. startp Osition = (mthreadcount-1) * range; subbean. endposition = filesize-1; mbeans. add (subbean);} else {// if it is equal to 0, the system will initialize N 0 sub-loaders for (INT n = 0; n <mthreadcount-1; N ++) {downloadbean subbean = (downloadbean) bean. clone (); subbean. threadid = N; mbeans. add (subbean);} downloadbean subbean = (downloadbean) bean. clone (); subbean. threadid = mthreadcount-1; mbeans. add (subbean);} mdboper. adddownlo Adtask (mbeans); If (bean. filesize> 0) {// if the file size has been obtained, it enters the waiting state. mstate = engineconstants. download_state_waitting; // The downloader enters the waiting state} else {// if the file size is not obtained, enable the thread to get the file size and update the content of the subloader new thread (New runnable () {@ override public void run () {Boolean flag = false; synchronized (lock_getfilesize) {flag = getfilesizebynetwork (mbean);} If (FLAG) {mstate = engineconstants. download_state_waitting; // The downloader enters the waiting state} else {Log. E (TAG, "failed to get file size from network 1 ");}}}). start () ;}} catch (clonenotsupportedexception e) {e. printstacktrace () ;}} else {callbackerror ("adddownloaderinfotodb error, possibly because enginedboperator is null. "); throw new downloadererrorexception (" adddownloaderinfotodb error, it may be that enginedboperator is null. ") ;}}/***** read the downloaded device information from the database ** @ Param bean * @ throws downloadererrorexception */private void getdownloaderinfofromdb (downloa Dbean) throws downloadererrorexception {If (mdboper! = NULL) {mbeans. clear (); mbeans = mdboper. getdownloadtaskbyurl (bean. URL); mbean. currentposition = 0; mbean. filesize = 0; mthreadcount = mbeans. size (); For (downloadbean subbean: mbeans) {mbean. currentposition + = subbean. currentposition; If (subbean. filesize> mbean. filesize) {mbean. filesize = subbean. filesize ;}} if (mbean. filesize <1) {New thread (New runnable () {@ override public void run () {Boolean flag = false; synchronized (lock_getfilesize) {flag = getfilesizebynetwork (mbean);} If (FLAG) {mstate = engineconstants. download_state_waitting; // The downloader enters the waiting state} else {log. E (TAG, "failed to get file size from Network 2 ");}}}). start ();} else {mstate = engineconstants. download_state_waitting; // The downloader enters the waiting state} else {callbackerror ("getdownloaderinfofromdb error, may be enginedboperator is null. "); throw new D Ownloadererrorexception ("getdownloaderinfofromdb error, may be enginedboperator is null. ") ;}}/*** get the file size from the network and update listbeans */private Boolean getfilesizebynetwork (downloadbean bean) {httpurlconnection connection = NULL; long filesize = bean. filesize; try {If (filesize <= 0) {// obtain the URL url = new URL (bean. URL); connection = (httpurlconnection) URL. openconnection (); connection. set Connecttimeout (5000); connection. setreadtimeout (8000); If (Android. OS. build. version. sdk_int> 10) {// circumvent 2. connection timeout bug caused by setrm added on X. setrequestmethod ("head"); // head} int resopnsecode = connection. getresponsecode (); If (resopnsecode! = 200 & resopnsecode! = 206) {callbackerror ("Incorrect HTTP return code:" + resopnsecode); Return false;} // obtain the file size filesize = connection. getcontentlength (); mbean. filesize = filesize; If (filesize <= 0) {callbackerror ("file size cannot be obtained from the server" + filesize); Return false;} // If (connection. getheaderfield ("content-range") = NULL) {// log. E (TAG, "the server does not support resumable data transfer"); // mthreadcount = 1; // if no storage space is available if (! Hasspaceinsdcard () {return false;} long range = filesize/mthreadcount; // file segment value // update listbean for (INT I = 0; I <mthreadcount-1; I ++) {downloadbean subbean = mbeans. get (I); subbean. filesize = filesize; subbean. startposition = I * range; subbean. endposition = (I + 1) * Range-1;} downloadbean subbean = mbeans. get (mthreadcount-1); subbean. filesize = filesize; subbean. startposition = (mthr Eadcount-1) * range; subbean. endposition = filesize-1; // update the database if (mdboper! = NULL) {mdboper. updatetaskcompletesize (mbeans, mbean. URL);} else {callbackerror ("getfilesizebynetwork error, which may be enginedboperator is null. "); throw new downloadererrorexception (" getfilesizebynetwork error, which may be enginedboperator is null. ");} return true;} else {// exit return true if the file size exists;} catch (exception E) {callbackerror ("getting file size from server timeout"); E. printstacktrace ();} finally {If (connection! = NULL) {connection. disconnect () ;}} return false;}/*** start download. Multiple calls may be made to */Public void startdownloader () {If (mstate = engineconstants. download_state_downloading) {// return if the download is in progress;} If (mbean = NULL) {callbackerror ("the downloader is not initialized"); return ;} file file = new file (mbean. savepath); file parentdirectory = file. getparentfile (); If (! Parentdirectory. exists () {parentdirectory. mkdirs ();} If (! File. exists () {try {file. createnewfile ();} catch (ioexception e) {e. printstacktrace () ;}} if (mbeans. size () <1) {// prevents the mbeans list from being cleared due to an error, but re-starts the task. All mbeans to be initialized again try {adddownloaderinfotodb (mbean );} catch (downloadererrorexception e) {e. printstacktrace (); Return ;}}/*** starts downloading only after obtaining the file size */synchronized (lock_getfilesize) {If (mstate = engineconstants. download_state_init) {// An error occurred while obtaining the file size., Re-obtain Boolean flag = getfilesizebynetwork (mbean); If (! Flag) {callbackerror ("failed to get file size"); Return ;}} mstate = engineconstants. download_state_downloading; mdboper. removepausefilebyurl (mbean. URL); // remove the mdonethreadcount = 0 from the pause list; // Number of initialization completed threads for (downloadbean Bean: mbeans) {If (bean. currentposition <(bean. endposition-bean. startposition) {// If the thread is not downloaded, hamalthread = new hamalthread (bean); hamalthread. start ();} else {// The completed thread does not need to be duplicated Create mdonethreadcount ++;} If (mdonethreadcount = mthreadcount) {// download downloaderdone () ;}} private class hamalthread extends thread {private int threadid; private long startpos; private long endpos; private long compeletesize; private string urlstr; Public hamalthread (downloadbean bean) {This. threadid = bean. threadid; this. startpos = bean. startposition; this. endpos = bean. endposition; this. Compeletesize = bean. currentposition; this. urlstr = bean. URL ;}@ override public void run () {httpurlconnection connection = NULL; randomaccessfile = NULL; inputstream is = NULL; try {URL url = new URL (urlstr ); connection = (httpurlconnection) URL. openconnection (); connection. setconnecttimeout (5000); connection. setreadtimeout (8000); connection. setrequestmethod ("get"); If (mthrea Dcount> 1) {// multi-thread download // set the range in the format of range: bytes X-y; connection. setrequestproperty ("range", "bytes =" + (startpos + compeletesize) + "-" + endpos);} randomaccessfile = new randomaccessfile (mbean. savepath, "RWD"); randomaccessfile. seek (startpos + compeletesize); // write the file to be downloaded to the file saved in the SAVE path is = connection. getinputstream (); byte [] buffer = new byte [buffersize]; int length =-1; engineutil eutil = engineut Il. getinstance (); If (enginevariable. support_network_type = engineconstants. download_network_onlywifi) {// If only 3G download if (eutil. getnetworktype ()! = Engineconstants. network_state_wifi) {// and the current network is not WiFi interruptdownloader (); Return ;}} while (length = is. Read (buffer ))! =-1) {// determine the network if (enginevariable. support_network_type = engineconstants. download_network_onlywifi) {// if it can only be 3G download if (eutil. getnetworktype ()! = Engineconstants. network_state_wifi) {// and the current network is not WiFi interruptdownloader (); Return ;}} randomaccessfile. write (buffer, 0, length); compeletesize + = length; synchronized (lock_refresh_progress) {mbean. currentposition + = length;} // update the download information mdboper in the database. updatetaskcompletesize (threadid, compeletesize, urlstr); If (mstate = engineconstants. download_state_pause | mstate = engineconstants. download_state_interrupt | mstate = engineconstants. download_state_stop | mstate = engineconstants. download_state_error) {// pause return ;}// the sub-thread downloads mdonethreadcount ++;} catch (exception e) {log. E (TAG, "the connection is disconnected during download... "); interruptdownloader (); E. printstacktrace ();} finally {try {is. close (); randomaccessfile. close (); connection. disconnect ();} catch (exception e) {e. printstacktrace () ;}} if (mdonethreadcount = mthreadcount) {downloaderdone () ;}}/ *** get download progress ** @ return */Public int getprogress () {If (mbean. filesize <1) {return 0;} return (INT) (mbean. currentposition * 100/mbean. filesize);}/*** pause download */Public void pausedownloader () {mstate = engineconstants. download_state_pause; mdboper. addpausefile (mbean. URL, mbean. packagename, mbean. fileid);}/*** interrupted download (not manually paused) */private void interruptdownloader () {mstate = engineconstants. download_state_interrupt;}/*** end download */Public void stopdownloader () {mstate = engineconstants. download_state_stop; mbean. currentposition = 0; removedownloaderinfo (mbean. URL);}/*** clear the downloaded information ** @ Param urlstr */private void removedownloaderinfo (string urlstr) {mdboper. deletedownloadtaskbyurl (urlstr); mdboper. removepausefilebyurl (urlstr); mbeans. clear ();}/*** download completed */private void downloaderdone () {mstate = engineconstants. download_state_done; mbean. donetime = system. currenttimemillis (); mcallback. callbackwhendownloadtasklistener (mstate, mbean, mbean. filename + "downloaded"); removedownloaderinfo (mbean. URL); mdboper. addcompletetask (mbean); // Save the completion information to the database}/*** callback when an error occurs ** @ Param info */private void callbackerror (string info) {mstate = engineconstants. download_state_error; mcallback. callbackwhendownloadtasklistener (mstate, mbean, Info); removedownloaderinfo (mbean. URL);}/*** determine whether there is sufficient space on the SD card */private Boolean hasspaceinsdcard () {If (mbean. filesize> engineutil. getinstance (). getfreespaceatdirectory (environment. getexternalstoragedirectory (). getabsolutepath () {callbackerror ("insufficient memory card space"); Return false;} return true ;}}

 

You are welcome to offer suggestions and improvement methods.

For the entire architecture, see the source code. It is definitely worth your favorites! This is free of charge. No, you should not doubt that commercial-level source code is free of charge.
If you feel better, please download http://www.5577.com/5577.apk.

Source code: http://download.csdn.net/detail/h3c4lenovo/5987789

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.