Android/java HTTP multi-threaded breakpoint download (attached source)

Source: Internet
Author: User

First look at the project structure:

HTTP multi-threaded breakpoint download involves the database, multi-threaded and HTTP requests, such as several modules, things are not many, want to find out is not very difficult, and then I share with you my approach.

First, look at the Mainactivity.java

Member variables, mainly the variables and handler of some download processes

        private string path = "http://192.168.1.3:8080/wanmei/yama.apk";p rivate string sdcardpath;private int threadnum = 5; ProgressDialog dialog;//Download Progress private int process;//Download complete percent private int done;private int filelength;//Before this download starts, The downloaded volume that has been completed by the private int completed;//thread pool is to be able to gracefully interrupt threads to download Executorservice pool; @SuppressLint ("Handlerleak") Private Handler Handler = new Handler () {public void Handlemessage (Android.os.Message msg) {process + = Msg.arg1;done = (int) ((1.0 * PROCE SS/FILELENGTH) * 100); LOG.I ("Process", "process" + done);d ialog.setprogress (done),//show dialogif when not showing dialog for the first time (do = = 100) {//Prompt user to download complete// After the thread download is complete, the cache data dbservice.getinstance (Getapplicationcontext ()) in the database is deleted. Delete (path);//The effect of a delay, you can let the user see a little more 100%timer Timer = new timer (), Timer.schedule (new TimerTask () {@Overridepublic void run () {Dialog.dismiss ();}}, 1000);}};};

Download method triggers the download event, first check if there is an SD card before starting the thread download

public void Download (View v) {completed = 0;process = 0;done = 0;pool = Executors.newfixedthreadpool (threadnum); Initprogre Ssdialog (); new Thread () {public void run () {try {if (Environment.getexternalstoragestate (). Equals (Environment.media_ Mounted)) {Sdcardpath = Environment.getexternalstoragedirectory (). GetAbsolutePath ();} else {toast ("No memory Card"); return;} Download (path, threadnum);} catch (Exception e) {e.printstacktrace ();}};}. Start ();}

Before we actually start the download, we have to make an HTTP request to get the size and file name of the downloaded file, prepare the size of the local file beforehand, and the area that each thread should download. This time we request the information in the response header, only need to request the head on the line, both shorten the response time, also can save traffic

public void Download (String path, int threadsize) throws Exception {Long startTime = System.currenttimemillis (); URL url = new URL (path);//Httphead head = new Httphead (path); HttpURLConnection conn = (httpurlconnection) url.openconnection ();//Here only need to get Httphead to the request header file, do not need body,//not only to shorten the response time, can also save flow//Conn.setrequestmethod ("GET"), Conn.setrequestmethod ("HEAD"), Conn.setconnecttimeout (5 * 1000); map<string, list<string>> headermap = Conn.getheaderfields ();iterator<string> Iterator = Headermap.keyset (). iterator (); while (Iterator.hasnext ()) {String key = Iterator.next (); list<string> values = Headermap.get (key); SYSTEM.OUT.PRINTLN (key + ":" + values.tostring ());} Filelength = Conn.getcontentlength ();//Gets the length of the file to download long endTime = System.currenttimemillis (); LOG.I ("Spend", "spend time =" + (endtime-starttime)); String filename = getfilename (path),//Gets the file name from the path, a filename, a ' new file ' (Sdcardpath + "/download/"); File.exists ()) {file.mkdirs ();} File SaveFile = new file (Sdcardpath +"/download/" + filename); Randomaccessfile accessfile = new Randomaccessfile (SaveFile, "RWD"); Accessfile.setlength (filelength);// Set the length of the local file to the same accessfile.close () as the download file;//calculate the length of data downloaded per thread <strong>int block = filelength% Threadsize = = 0? Filelength/threadsize:filelength/threadsize + 1;</strong>//judgment is not the first time to download, not just calculate how many if (!) has been downloaded. Dbservice.getinstance (Getapplicationcontext ()). Ishasinfors (Path)) {for (int threadid = 0; ThreadID < threadnum; threadid++) {completed + = Dbservice.getinstance (Getapplicationcontext ()). Getinfobyidandurl (ThreadID, Path);}}                Message msg = Handler.obtainmessage (); &NBSP;MSG.ARG1 = Completed;handler.sendmessage (msg); for (int threadid = 0; ThreadID < threadsize; threadid++) {Pool.ex Ecute (New Downloadthread (Getapplicationcontext (), Path,savefile, block, ThreadID, threadnum). Setondownloadlistener ( This));}}
Downloadthread.java

There are two points: 1, Google recommended httpurlconnection, I tried to download the speed is really faster than httpclient

2, download the time used to cache the byte array, his length affects the speed of download

@Overridepublic void Run () {log.i ("Download", "Thread ID:" + threadid + "start download");//Calculate start position formula: Thread id* The length of the downloaded data per thread + downloaded completed (breakpoint continuation) =? Calculate End Position formula: (thread ID + 1) * The length of data downloaded per thread-1 =?completed = dbservice.getinstance (context). Getinfobyidandurl (ThreadID, URL); int startposition = ThreadID * Block+completed;int endposition = (ThreadID + 1) * Block-1;try {randomaccessfile ACCESSFI Le = new Randomaccessfile (SaveFile, "RWD"); Accessfile.seek (startposition);//set from where to start writing data//I test, Download faster than httpclient with httpurlconnection 10 times times faster than httpurlconnection conn = (httpurlconnection) new URL (URL). OpenConnection (); Conn.setrequestmethod ("GET"); Conn.setconnecttimeout (5 * +); Conn.setrequestproperty ("Accept-language", "Zh-CN") ; Conn.setrequestproperty ("Accept", "Image/gif, Image/jpeg, Image/pjpeg," + "image/pjpeg, application/ X-shockwave-flash, "+" Application/xaml+xml, application/vnd.ms-xpsdocument, "+" APPLICATION/X-MS-XBAP, application/ X-ms-application, "+" application/vnd.ms-excel, Application/vnd.ms-powerpoint, "+" Application/msword, */* "); Conn.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) "); Conn.setrequestproperty (" Referer ", url), Conn.setrequestproperty (" Connection "," keep-alive "); Conn.setrequestproperty ("Range", "bytes=" + startposition + "-" + endposition);//Set the range to get Entity Data//HttpClient HttpClient = NE W defaulthttpclient ();//HttpGet HttpGet = new HttpGet (URL);//Httpget.addheader ("Range",//"bytes=" +startposition+ "-" +endposition);//HttpResponse response = Httpclient.execute (httpget); InputStream instream = Conn.getinputstream ();// It should be noted here that the length of the array actually represents the size of each download stream//If it is too small, for example, 1024, each time will only download 1024byte content, the speed is too slow,//for downloading more than 10 trillion files is too difficult, too small is equivalent to the speed limit//But also can not be too big, if too big , then the data in the buffer is too large, resulting in oom//in order not to oom and can open the maximum speed, here can get the application available content, dynamically assigned int freememory = ((int) runtime.getruntime (). Freememory ()) ;//Get application remaining available memory byte[] buffer = new byte[freememory/threadnum];//available memory split to several threads//byte[] buffer = new Byte[1024];int len = 0;int total = 0;boolean Isinterrupted=false;while (len = instream.read (buffer))! =-1) {Accessfil E.write (buffer, 0, Len); total + = Len; LOG.I ("Download", "Thread ID:" + threadid + "downloaded" + total + "all" + block);//real-time Update progress Listener.ondownload (Threadid,len,total,url );//When the thread is signaled to be interrupted, exit the loop and terminate the download Operation <strong>if (thread.interrupted ()) {isinterrupted=true;break;} </strong>}instream.close (); Accessfile.close (); if (isinterrupted) {log.i ("Download", "Thread ID:" + threadid + "Download Stop") );} ELSE{LOG.I ("Download", "Thread ID:" + threadid + "Download Complete");}} catch (Exception e) {e.printstacktrace ();}}

I am in the application back to the background, let stop download, not why, just don't want to write that button, need to write their own.

Here, I try to break all threads through the thread pool's shutdownnow (), not actually interrupts, just after this method is called, the line thread's thread.interrupted () method returns True, and then I exit the loop by breaking; To achieve the purpose of interrupting the download.

@Overrideprotected void OnStop () {super.onstop ();//The app pauses to download Pool.shutdownnow ();d Ialog.dismiss () when it is back in the background;}
Interface callbacks

Update progress to the database, in theory, progress should not be updated in real time, SQLite is also a file in nature, frequently open close files too much resources, so in the actual project should be in the user pause or break the network and other special circumstances before updating the progress

@Overridepublic void ondownload (int threadId, int process, int completed, String URL) {//Update progress to database, in theory, progress should not be updated in real time,//sqli Te is also essentially a file, frequently open close files too much resources,//So in the actual project should be in the user pause or break the network and other special circumstances only update progress dbservice.getinstance (Getapplicationcontext ()). Updatainfos (threadid,completed, URL); Message msg = Handler.obtainmessage (); msg.arg1 = Process;handler.sendmessage (msg);}

Dbservice.java

Package Com.huxq.multhreaddownload;import Java.util.arraylist;import Java.util.list;import android.content.Context ; Import Android.database.cursor;import Android.database.sqlite.sqlitedatabase;import Android.util.Log;public class  Dbservice {private DBHelper dbhelper;private static Dbservice instance;private Dbservice (context context) {DBHelper = new DBHelper (context);}  /** * Singleton mode, do not have to re-use each time new * * @param context * @return */public static Dbservice getinstance (context context) {if (instance = = null) {synchronized (Dbservice.class) {if (instance = = null) {instance = new Dbservice (context); return instance;}}} return instance;} /** * To see if there is data in the database */public boolean ishasinfors (String urlstr) {sqlitedatabase database = Dbhelper.getreadabledatabase (); String sql = "SELECT COUNT (*) from Download_info where url=?"; cursor cursor = database.rawquery (sql, new string[] {urlstr}); Cursor.movetofirst (); int count = Cursor.getint (0); LOG.I ("Count", "count=" + count); Cursor.close (); return count = = 0;} /** * SaveDownload specific information */public void Saveinfos (list<downloadinfo> infos) {sqlitedatabase database = Dbhelper.getwritabledatabase (); for (Downloadinfo info:infos) {String sql = ' INSERT INTO Download_info (Thread_id,start_ POS, "+" End_pos,compelete_size,url) VALUES (?,?,?,?,?) "; O Bject[] Bindargs = {Info.getthreadid (), Info.getstartpos (), Info.getendpos (), Info.getcompeletesize (), INFO.GETURL ()} ;d atabase.execsql (SQL, Bindargs);}} /** * Get download specific information */public list<downloadinfo> Getinfos (String urlstr) {list<downloadinfo> List = new ARRAYLIST&L T;downloadinfo> (); Sqlitedatabase database = Dbhelper.getreadabledatabase (); String sql = "Select thread_id, Start_pos, End_pos,compelete_size,url" + "from Download_info where url=?"; cursor cursor = database.rawquery (sql, new string[] {urlstr}), while (Cursor.movetonext ()) {Downloadinfo info = new DOWNL Oadinfo (cursor.getint (0), Cursor.getint (1), Cursor.getint (2), Cursor.getint (3), cursor.getstring (4)); List.add (info );} Cursor.close (); return list;} /** * GetThe progress of a specific ID thread has been downloaded * * @param ID * @param URL * @return */public synchronized int getinfobyidandurl (int id, String URL) {sqlit Edatabase database = Dbhelper.getreadabledatabase (); String sql = "Select Compelete_size" + "from Download_info where thread_id=? and url=? "; cursor cursor = database.rawquery (sql, new string[] {ID + "", url}); if (Cursor!=null&&cursor.movetofirst ()) {Log . I ("Count", "thread id=" + id+ "completed=" + cursor.getint (0)); return Cursor.getint (0);} return 0;} /** * Update the download information in the database */public synchronized void Updatainfos (int threadId, int compeletesize, String urlstr) {sqlitedatabase D Atabase = Dbhelper.getreadabledatabase ();//If there is an update, it does not exist insert string sql = "Replace into Download_info" + "(Compelete_size, Thread_id,url) VALUES (?,?,?) "; O Bject[] Bindargs = {compeletesize, threadId, urlstr};d atabase.execsql (sql, Bindargs);} /** * Close database */public void Closedb () {dbhelper.close ();} /** * Delete data in database after download is complete */public void delete (String URL) {sqlitedatabase database = Dbhelper.getreadabledatabASE (); int count = Database.delete ("Download_info", "Url=?", new string[] {URL}); LOG.I ("delete", "delete count=" +count);d atabase.close ();}  public void Saveorupdateinfos () {}public synchronized void deletebyidandurl (int id, String URL) {sqlitedatabase database = Dbhelper.getreadabledatabase (); int count = Database.delete ("Download_info", "thread_id=?") And url=? ", new string[] {ID +" ", url}); LOG.I ("delete", "Delete id=" +id+ "," + "count=" +count);d atabase.close ();}}

Writing these things also took me a little time, because there are a lot of things involved, and finally I will postDEMO, interested can see, if in doubt, welcome message or contact me, discuss together.

Android/java HTTP multi-threaded breakpoint download (attached source)

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.