Android enables multi-threaded breakpoint Continuation

Source: Internet
Author: User

Foreword: The project is fast delivery stage, the customer said to change a demand, add a breakpoint continuation function. A breakpoint is added when the version is updated, the magazine is downloaded, or the video is downloaded. Due to the time constraints, think of a demo code before, it is directly modified to use, according to their own way, but the core code has not changed. May be used in the future, so he wrote a special demo.

First look at the project directory structure:

    1. DB---> Operations database (CREATE database tables, data additions and deletions. )
    2. Util---> Tool class
    3. Download---> Implementation downloads (Downloader and custom threads. )

Here, for example, the download of the easy-to-use client is briefly introduced.
String Downloadpath = ""; String fileName = "easy-to-trust apk";

Here I added the notification bar to see the progress.

General idea: Download the total size of the file according to your needs, you can customize several threads to download the action at the same time (here I to the download constructor method overload, the default is not set the number of threads by default is 3).
Internally use map key-value pairs to cache threads to download data, key is thread Id,value: is the amount of downloads. There is also an array of threads, which corresponds to the previous map.
In the downloader, there is a loop that constantly checks to see if each thread's download task is completed, then it is finished, and then it is done, so that after the final completion, exit the loop and the entire download task is completed. Delete the download record from the database table.

Each thread then assigns a download file size value to perform the download. During the download process, through the callback interface, callback to the mainactivity screen, with the handler implementation of the update UI.
Here are the details of the problem, ah there are many, the general idea is this.
In the code I have written detailed comments, post code to put. I hope you can read it.

Package;import;import;import;import;import;import Com.example.util.common;import android.util.Log;/** * The thread used to download the file. The line threads the amount of work allocated: Block * */public class Downloadthread extends Thread {private static final String TAG = "Downloadthread";/** * Destination file */private file savefile;/** * files download path */private URL downurl;/** * Current thread needs to download file size */private int block;/** * Thread Identification ID * /private int threadId = -1;/** * Previously downloaded location */private int downlength;/** * Determine if the current thread is ending */private boolean isfinished = false; /** * File Downloader */private filedownloader downloader;/** * @param downloader * Downloader * @param downurl * Downloaded Network path * @param saveFile * saved target file * @param block * Download Task volume * @param downlength * Already downloaded size * @ PARAM threadId * thread ID */public downloadthread (filedownloader downloader, URL downurl,file saveFile, int block, int downlength, int threadId) {thiS.downurl = Downurl;this.savefile = Savefile;this.block = Block;this.downloader = Downloader;this.threadid = ThreadId; This.downlength = Downlength;} @Overridepublic void Run () {if (Downlength < block) {//not downloaded finish try {//download HttpURLConnection http = common.gethttppa using get mode  Rams (Downurl);//start download location int startposition = block * (threadId-1) + downlength;//end download location int endposition = block * threadId -1;//setting gets the range of Entity Data Http.setrequestproperty ("range", "bytes=" + startposition + "-" + endposition);//Get file input stream InputStream in Stream = Http.getinputstream (); byte[] buffer = new Byte[1024];int offset = 0;print ("Thread" + this.threadid+ "start Down" Load from position "+ endposition); Randomaccessfile threadfile = new Randomaccessfile (This.savefile, "RWD"); (endposition); while (offset = (buffer, 0, 1024x768))! =-1) {threadfile.write (buffer, 0, offset);//download cumulative Downlength + = offset;//Update download Database downl Oader.update (This.threadid, Downlength);d ownloader.append (offset);} Threadfile.close (); inStReam.close ();p rint ("Thread" + This.threadid + "Download Finish");//Set download complete flag bit. This.isfinished = true;} catch (Exception e) {this.downlength = -1;print ("Thread" + This.threadid + ":" + E);}}} /** * Print log information * * @param msg */private static void print (String msg) {log.i (TAG, msg);} /** * Download Completed * * @return */public boolean isfinish () {return isfinished;} /** * Downloaded content size * * @return If the return value is-1, the download fails */public long getdownlength () {return downlength;}}

Download Device:

Package;import;import;import;import;import;import;import Java.util.linkedhashmap;import;import Java.util.uuid;import Java.util.concurrent.ConcurrentHashMap; Import Java.util.regex.matcher;import Java.util.regex.pattern;import Android.content.context;import Android.util.log;import com.example.db.dbtools;import com.example.util.common;/** * * File Download * * * */public class FileDo Wnloader {private static final String TAG = "Filedownloader";p rivate Context context;/** * Operations Database class */private DBTools Dbtoo ls;/** * Downloaded file length */private int downloadsize = 0;/** * Original file length */private int fileSize = 0;/** * Number of threads */private Downloadthread [] threadarr;/** * Save files locally */private file savefile;/** * default number of download threads */private static final int defaultthreadsize = 3;/** * Default File Download storage location */private static String Defaultdestpath = "";/** * used to cache the length of each thread download * <p> * Key:corresponding thread ID; Value: The length of the corresponding thread has been downloaded * </p> */private map<integer, integer> cachedownmap = new Concurrenthashmap<integer, Integer> ();/** * Each thread should download the length */private int block;/** * File download path */private String downloadurl;/** * Get the number of threads */public int GE Tthreadsize () {return threadarr.length;} /** * Get File Size * * @return need to download the total length of the file */public int getfilesize () {return fileSize;} /** * Cumulative file downloaded size * * @param size * Download volume now */protected synchronized void append (int size) {downloadsize + = size; }/** * Update the location of the last download of the specified thread * * @param threadId * thread ID * @param POS * Last downloaded location */protected synchronized voi d Update (int threadId, int pos) {this.cacheDownMap.put (threadId, POS); This.dbTools.update (This.downloadurl, THIS.CACHEDOWNMAP);}            /** * Build File Downloader * * @param downloadurl * Download Path * @param filesavedir * File Save directory * @param threadnum * Number of download Threads */public Filedownloader (context context, string DownloadURL, String Destpath,int threadnum) {this.context = c Ontext;this.dowNloadurl = Downloadurl;dbtools = new DbTools (this.context); Checkpath (destpath); This.threadarr = new downloadthread[ Threadnum];setrequest (DownloadURL, destpath);} /** * Check if the download path exists and does not exist then create: * @param destpath * @return The existence of the directory */public Boolean checkpath (String destpath) {File File = new file (destpath); if (!file. Exists ()) {Boolean bol = File.mkdirs (); return bol;} return true;} /** * @param context * @param downloadurl */public Filedownloader (context context, String downloadurl) {this.context = con Text;this.downloadurl = Downloadurl;this.threadarr = new Downloadthread[defaultthreadsize];this.dbtools = new DbTools ( This.context);d btools = new DbTools (this.context); Checkpath (defaultdestpath); This.threadarr = new downloadthread[ Defaultthreadsize];setrequest (DownloadURL, Defaultdestpath);} /** * Encapsulation Request */public void Setrequest (String downurl, String destpath) {URL url = null;try {url = new URL (downurl); HttpURLConnection conn = common.gethttpparams (URL); conn.connect ();//Print header information Printresponseheader (conn);//200== "Successfully connected ... if (conn.getresponsecode () = = 200) {//Get total file Size this.filesize = Conn.getcontentlength (); if ( This.filesize <= 0) throw new RuntimeException ("The file most likely does not exist ...");//Gets the file name currently required to download string filename = GetFileName (conn);// The target saves the file This.savefile = new files (destpath, filename);//Gets the current path of the download record including the quantity already downloaded. Map<integer, integer> logdata = Dbtools.getdata (Downurl);//If there is a download record to put the length of data downloaded by each thread into the cache variable if (logdata.size () > 0) {for (Map.entry<integer, integer> entry:logdata.entrySet ()) Cachedownmap.put (Entry.getkey (), Entry.getvalue ());} The following calculates the length of the data that the thread has downloaded if (this.cacheDownMap.size () = = This.threadArr.length) {for (int i = 0; i < this.threadArr.length; i++) {this.downloadsize + = This.cacheDownMap.get (i + 1);} Print ("Length of downloaded data" + this.downloadsize); Calculate the length of data assigned to each thread downloaded This.block = (this.filesize% this.threadArr.length) = = 0? This.filesize/this.threadarr.length:this.filesize/this.threadarr.length + 1;} else {throw new RuntimeException ("no response ...");}} catch (Malformedurlexception e) {E.printstacktrace ();} catch (IOException e) {e.printstacktrace ();}} /** * Get filename * * @param conn * This HTTP connection * @return */private String GetFileName (httpurlconnection conn) {//Get file Name string filename = this.downloadUrl.substring (this.downloadUrl.lastIndexOf ('/') + 1); if (filename = = NULL | | ". Equals (Filename.trim ())) {//If the file name is not obtained for (int i = 0;; i++) {String mine = Conn.getheaderfield (i), if (mine = = null) break;if ("Content-disposition". Equals ( Conn.getheaderfieldkey (i). toLowerCase ()) {Matcher match = Pattern.compile (". *filename= (. *)"). Matcher ( Mine.tolowercase ()); if (Match.find ()) return (1);}} The default filename = Uuid.randomuuid () + ". tmp";//default takes a filename}return filename;} /** * Start Download file * * @param listener * Monitor the number of downloads changes, if you do not need to know the number of live downloads, you can set to NULL * @return downloaded file size * @throws Exception */ public int startdownload (Downloadprogresslistener listener) throws Exception {try {randomaccessfile randout = new Randomaccessfile (This.savefile, "RW");//Determine the length of the original file if (this.filesize; 0) Randout.setlength (this.filesize); Randout.close (); URL url = new URL (this.downloadurl);//cache count and number of threads set original value if (this.cacheDownMap.size ()! = this.threadArr.length) { This.cacheDownMap.clear (); for (int i = 0; i < this.threadArr.length; i++) {this.cacheDownMap.put (i + 1, 0);//Initialize each thread already  The downloaded data length is 0}}//open thread for download for (int i = 0; i < this.threadArr.length; i++) {int downlength = This.cacheDownMap.get (i + 1);// The first condition here is to determine that the current thread has not downloaded the allocated quantity, and the second is to determine that the current total download volume is less than the total size of the file that needs to be downloaded. if (Downlength < this.block&& this.downloadsize < this.filesize) {This.threadarr[i] = new DownloadThread ( This, url,this.savefile, this.block,this.cachedownmap.get (i + 1), i + 1);//Increase Priority this.threadarr[i].setpriority (7); This.threadarr[i].start ();} else {//The thread has finished the task and T is off. This.threadarr[i] = null;}} Insert download data into Database (This.downloadurl, This.cachedownmap); Boolean notfinish = true;//Download Incomplete// It is a dead loop before the file is fully downloaded, judging if all threads are finished downloading//if the For loop ends, the outer while loop ends. while (notfinish) {thread.sleep (n); notfinish = false;//assumes all threads download complete foR (int i = 0; i < this.threadArr.length; i++) {if (This.threadarr[i]! = null&&!this.threadarr[i].isfinish ()) { If the discovery thread does not complete the download notfinish = true;//setting flag for the download does not complete//Gets the current thread to complete the task amount, if 1 is re-downloaded. if (this.threadarr[i].getdownlength () = =-1) {This.threadarr[i] = new Downloadthread (this, url,this.savefile, This.block,this.cachedownmap.get (i + 1), i + 1); this.threadarr[i].setpriority (7); This.threadarr[i].start ();}}} Callback, update uiif (listener! = null) listener.ondownloadsize (this.downloadsize);//Notifies the data length that has been downloaded to complete}//file download complete delete download record. Dbtools.delete (This.downloadurl);} catch (Exception e) {print (e.tostring ()); throw new Exception ("File download Fail"); return this.downloadsize;} /** * Get HTTP response header fields * * @param http * @return */public static map<string, string> Gethttpresponseheader (Httpurlconnec tion http) {map<string, string> header = new linkedhashmap<string, string> (); for (int i = 0;; i++) {String min E = Http.getheaderfield (i); if (mine = = null) break;header.put (Http.getheaderfieldkey (i), mine);} return header;} /** * Print HTTP header field * * @param http */public static void Printresponseheader (HttpURLConnection http) {map<string, STRING&G T Header = Gethttpresponseheader (HTTP); for (map.entry<string, string> entry:header.entrySet ()) {String key = Entry. GetKey ()! = null? Entry.getkey () + ":": "";p rint (key + Entry.getvalue ());}} /** * Print log information * * @param msg * Printed log contents */private static void print (String msg) {log.i (TAG, msg);} /** * Download File monitoring * * mainly used for callbacks. */public interface Downloadprogresslistener {public void ondownloadsize (int size);}}

Package Com.example.util;import;import;import;/** * <  p> * </p> * * @author XIANGXM */public class Common {/** * format file Large * * @param volume * File size * @return Formatted character */public static String Getvolume (long volume) {float num = 1.0F;  String str = null;if (Volume < 1024x768) {str = volume + "B";} else if (Volume < 1048576) {num = num * volume/1024;str = String.Format ("%.1f", num) + "K";} else if (Volume < 1073741824) {num = num * volume/1048576;str = String.Format ("%.1f", num) + "M";} else if (volume &L T 1099511627776L) {num = num * volume/1073741824;str = String.Format ("%.1f", num) + "G";} return str;} /** * * Set network parameters */public static httpurlconnection gethttpparams (URL httpurl) {httpurlconnection Http;try {http = (HTTPURLC onnection) httpurl.openconnection () http.setconnecttimeout (5 * +); Http.setrequestmethod ("GET"); Http.setrequestproperty ("Accept", "Image/gif, Image/jpeg, Image/pjpeg, Image/pjpeg, aPplication/x-shockwave-flash, Application/xaml+xml, Application/, APPLICATION/X-MS-XBAP, Application/x-ms-application, Application/, Application/, Application/msword, */* "); Http.setrequestproperty ("Accept-language", "ZH-CN"); Http.setrequestproperty ("Referer", httpurl.tostring ()); Http.setrequestproperty ("Charset", "UTF-8"), Http.setrequestproperty ("User-agent", "mozilla/4.0" (compatible; MSIE 8.0; Windows NT 5.2; trident/4.0;. NET CLR 1.1.4322;. NET CLR 2.0.50727;. NET CLR 3.0.04506.30;. NET CLR 3.0.4506.2152;. NET CLR 3.5.30729); h Ttp.setrequestproperty ("Connection", "keep-alive"); return http;} catch (IOException e) {e.printstacktrace ();} return null;}}

Source code:

Take a look:

Next: use Downloadmanager to achieve download, the breakpoint continues to pass.

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: 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.