Reprint Please specify source: http://blog.csdn.net/zhaokaiqiang1992
On the first day of work, in the technology group and everyone gossip, inadvertently talked about the use of the framework, a classmate said in order to use the xutils of the broken line to download the function, the entire library into the project, in Google's official recommendations, is very not recommended this practice, the collection framework, although a lot of functions integrated, But the more code, the more likely the problem, and the invisible increase in the size of the APK, therefore, not worth the candle. Therefore, this article mainly on the "disconnection continued" Download function, the simple idea and code implementation, because this kind of code is more, so found a good write demo, simple optimization of a bit.
Before pasting the code, let's analyze the requirements and solve the ideas. The first is the download function, we simply use the httpurlconnection can be, no need to introduce the framework, and then the breakpoint continues to pass, in fact, the breakpoint continues to refer to is that we can stop our download task at any time, when the next time you start again, you can download from the last location to continue to download, Save download time, very convenient and very practical, just in the process of downloading, record the download to the location, when the download begins again, we continue to request the server from the last location. In this case, there is a class that has to mention, that is randomaccessfile, this class is the core class to implement the breakpoint continuation function, Randomaccessfile allows us to read and write from the location we want, so we can divide the file we want to download into several parts, And then open a number of threads, respectively, from a different location to download, so that all the parts are downloaded, we can get a complete file, this is the principle of multi-threaded download, complete the above steps, our multi-threaded disconnection download function is basically completed, Here is a demo on the internet, I made some changes to the code, from the code, we look at how to implement the code.
First, if you want to implement the continuation of the breakpoint, we have to record the location of the files downloaded by each thread, you can use the file, you can use the SP, you can use the DB, this demo uses the DB, we first look at the database helper implementation class, which stores the primary key, thread number, start position, end position , complete position and can.
Downloadhelper.java
public class Downloadhelper extends Sqliteopenhelper {private static final String Sql_name = "download.db";p rivate static Final int download_version = 1;public Downloadhelper (context context) {Super (context, sql_name, NULL, download_version);} /** * Create a download_info table store download information under the DOWNLOAD.DB database */@Overridepublic void OnCreate (Sqlitedatabase db) {Db.execsql ("Create Table Download_info (_id integer PRIMARY KEY autoincrement, thread_id Integer, "+" Start_pos integer, End_pos integer, Comp Elete_size Integer,url char) ");} @Overridepublic void Onupgrade (sqlitedatabase db, int oldversion, int newversion) {}}
with the helper, we're creating a SQL tool class that completes the data manipulation of the table
Downlaodsqltool.java
public class Downlaodsqltool {private Downloadhelper dbhelper;public Downlaodsqltool (context context) {DBHelper = new Dow Nloadhelper (context);} /** * Create specific information for download */public void Insertinfos (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.getwritabledatabase (); 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);} return list;} /** * Update the download information in the database */public void Updatainfos (int threadId, int compeletesize, String urlstr) {Sqlitedatabase db = DbH Elper.getwritabledatabase (); String sql = "Update download_info set compelete_size=?" where thread_id=? and url=? "; 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.getwritabledatabase ();d atabase . Delete ("Download_info", "Url=?", new string[] {URL});}}
database related classes on these, the function of the continuation of the breakpoint has been completed, the following see how to implement the download.
First, for ease of operation, we extract the entity class from the downloaded file
Downloadinfo.java
public class Downloadinfo {private int threadid;//downloader idprivate int startpos;//start point private int endpos;//end point private int Co mpeletesize;//Completion degree private String url;//the URL address of the download file public downloadinfo (int threadId, int startpos, int endpos,int compelet esize, String url) {this.threadid = Threadid;this.startpos = Startpos;this.endpos = Endpos;this.compeletesize = Compelete Size;this.url = URL;} Public Downloadinfo () {}public String getUrl () {return URL;} public void SetUrl (String url) {this.url = URL;} public int GetThreadId () {return threadId;} public void Setthreadid (int threadId) {this.threadid = threadId;} public int Getstartpos () {return startpos;} public void Setstartpos (int startpos) {this.startpos = startpos;} public int Getendpos () {return endpos;} public void Setendpos (int endpos) {this.endpos = Endpos;} public int getcompeletesize () {return compeletesize;} public void setcompeletesize (int compeletesize) {this.compeletesize = compeletesize;} @Overridepublic String toString () {return ' Downloadinfo [Threadid= "+ ThreadId +", startpos= "+ startpos+", endpos= "+ Endpos +", compeletesize= "+ compeletesize+"] ";}
after the entity class is extracted, we can implement the download function,Downloadhttptool is the main class to implement the download function
Downloadhttptool.java
public class Downloadhttptool {private static final String TAG = DownloadHttpTool.class.getSimpleName ();//number of threads private in T threadcount;//URL address private String urlstr;private Context mcontext;private Handler mhandler;//save Download Information class private List <DownloadInfo> downloadinfos;//Directory private string localpath;//file name private string filename;private int filesize;// File Information save database operation class private Downlaodsqltool sqltool;//uses enumerations to represent the three states of the downloaded state private enum download_state {downloading, Pause, ready, Delete;} Current download Status private download_state state = download_state.ready;//Total number of downloads for all threads private int globalcompelete = 0;public downloadh Ttptool (int threadcount, String urlstring,string LocalPath, String fileName, Context context, Handler Handler) {super (); t His.threadcount = Threadcount;this.urlstr = Urlstring;this.localpath = Localpath;this.mcontext = Context;this.mHandler = Handler;this.filename = Filename;sqltool = new Downlaodsqltool (mcontext);} Before you start the download, you need to call the Ready method to configure public void to be {LOG.W (TAG, "ready"); Globalcompelete = 0;downloadinfos = Sqltool.getinfos (URLSTR), if (downloadinfos.size () = = 0) {Initfirst ();} else {File file = new file (loc Alpath + "/" + FileName), if (!file.exists ()) {sqltool.delete (URLSTR); Initfirst ();} else {fileSize = Downloadinfos.get ( Downloadinfos.size ()-1). Getendpos (); for (Downloadinfo Info:downloadinfos) {globalcompelete + = Info.getcompeletesize ();} LOG.W (TAG, "Globalcompelete:::" + Globalcompelete);}} public void Start () {LOG.W (TAG, "start"); if (Downloadinfos! = null) {if (state = = download_state.downloading) {return;} State = Download_state.downloading;for (Downloadinfo info:downloadinfos) {log.v (TAG, "Startthread"); new Downloadthread (Info.getthreadid (), Info.getstartpos (), Info.getendpos (), Info.getcompeletesize (), INFO.GETURL ()). Start ();}}} public void Pause () {state = Download_state.pause;sqltool.closedb ();} public void Delete () {state = Download_state.delete;compelete (); new File (LocalPath + file.separator + fileName). Delete () ;} public void Compelete () {Sqltool.delete (urlstR); Sqltool.closedb ();} public int GetFileSize () {return fileSize;} public int getcompeletesize () {return globalcompelete;} /** * First download initializes */private void Initfirst () {LOG.W (TAG, "Initfirst"); try {URL url = new URL (urlstr); HttpURLConnection connection = (httpurlconnection) url.openconnection (); connection.setconnecttimeout (5000); Connection.setrequestmethod ("GET"); fileSize = Connection.getcontentlength (); LOG.W (TAG, "fileSize::" + fileSize); File Fileparent = new file (LocalPath), if (!fileparent.exists ()) {Fileparent.mkdir ();} File File = new file (fileparent, FileName), if (!file.exists ()) {file.createnewfile ();} Local Access file Randomaccessfile accessfile = new Randomaccessfile (file, "RWD"); Accessfile.setlength (fileSize); Accessfile.close (); Connection.disconnect ();} catch (Exception e) {e.printstacktrace ();} int range = Filesize/threadcount;downloadinfos = new arraylist<downloadinfo> (); for (int i = 0; i < ThreadCount -1; i++) {Downloadinfo info = new Downloadinfo (i, I * range, (i + 1) * range-1, 0, urlstr);d Ownloadinfos.add (info);} Downloadinfo info = new Downloadinfo (threadCount-1, (threadCount-1) * range, fileSize-1, 0, urlstr);d Ownloadinfos.add (info); Sqltool.insertinfos (Downloadinfos);} /** * Custom Download Thread * * @author Zhaokaiqiang * @time 2015-2-25 pm 5:52:28 */private class Downloadthread extends thread {private int threadid;private int startpos;private int endpos;private int compeletesize;private String urlstr;private int totalThr Eadsize;public downloadthread (int threadId, int startpos, int endpos,int compeletesize, String urlstr) {this.threadid = th Readid;this.startpos = Startpos;this.endpos = Endpos;totalthreadsize = endpos-startpos + 1;this.urlstr = urlstr;this.com Peletesize = compeletesize;} @Overridepublic void Run () {httpurlconnection connection = null; Randomaccessfile Randomaccessfile = Null;inputstream is = null;try {randomaccessfile = new Randomaccessfile (localPath+ Fi Le.separator + fileName, "RWD"); Randomaccessfile.seek (startpos + compeletesize); URL url = new URL (urlstr); connection = (HttpURLConnection) url.openconnection (); connection.setconnecttimeout (5000); Connection.setrequestmethod ("GET"); Connection.setrequestproperty ("Range", "bytes=" + (Startpos + compeletesize) + "-" + Endpos); is = Connection.getinputstream (); byte[] buffer = new Byte[1024];int length = -1;while ((length = is.read (buffer) )! =-1) {randomaccessfile.write (buffer, 0, length); compeletesize + = length; Message message = Message.obtain (); message.what = Threadid;message.obj = Urlstr;message.arg1 = length; Mhandler.sendmessage (message); LOG.W (TAG, "Threadid::" + Threadid + "Compelete::" + compeletesize + "total::" + totalthreadsize);//When the program is no longer in the download state, Record the current download progress if (state! = download_state.downloading) | | (Compeletesize >= totalthreadsize)) {Sqltool.updatainfos (threadId, Compeletesize, urlstr); break;}}} catch (Exception e) {e.printstacktrace (); Sqltool.updatainfos (ThreadId, Compeletesize, URLSTR);} finally {try {if (Is! = N ull) {is.close ();} Randomaccessfile.close (); connection.dIsconnect ();} catch (Exception e) {e.printstacktrace ();}}}}
In the above code, we define a thread for the multi-threaded download of the file and, when exiting the download state and completing the download, record the location of the download and save it to the database. In the original code, is not to get a data, access to a database, greatly increased the frequency of the operation of the database, reduce the efficiency, the original download about 420k files, need to operate 420 database, now only once can.
In the Initfirst (), the first initialization, based on the size of the download file and the number of open threads, the download entity classes are initialized and assigned values. After the Randomaccessfile is created, the Downloadinfo initialization is complete and you can download the file via start ().
In fact, here, the basic function has been realized. In order to make our operations more convenient, but also to monitor the progress of the download, we have the download class once encapsulated, the code is as follows:
Downloadutil.java
public class Downloadutil {private Downloadhttptool mdownloadhttptool;private ondownloadlistener Ondownloadlistener; private int filesize;private int downloadedsize = 0; @SuppressLint ("Handlerleak") private Handler Mhandler = new Handler () { @Overridepublic void Handlemessage (Message msg) {int length = msg.arg1;synchronized (this) {///locking guarantees the correctness of the download downloadedsize + = length;} if (Ondownloadlistener! = null) {ondownloadlistener.downloadprogress (downloadedsize);} if (downloadedsize >= fileSize) {mdownloadhttptool.compelete (); if (ondownloadlistener! = null) { Ondownloadlistener.downloadend ();}}}; Public downloadutil (int threadcount, string filePath, String filename,string urlstring, context context) { Mdownloadhttptool = new Downloadhttptool (threadcount, Urlstring,filepath, filename, context, mhandler);} Before the download begins, the async thread calls the Ready method to get the file size information, and then calls the Start method public void Start () {new asynctask<void, void, void> () {@ overrideprotected void Doinbackground (void ... arg0) {mdownloadhttptool.ready (); return null;} @Overrideprotected void OnPostExecute (void result) {fileSize = Mdownloadhttptool.getfilesize ();d ownloadedsize = Mdownloadhttptool.getcompeletesize (); LOG.W ("Tag", "Downloadedsize::" + downloadedsize); if (ondownloadlistener! = null) {Ondownloadlistener.downloadstart ( fileSize);} Mdownloadhttptool.start ();}}. Execute ();} public void Pause () {mdownloadhttptool.pause ();} public void Delete () {mdownloadhttptool.delete ();} public void Reset () {mdownloadhttptool.delete (); Start ();} public void Setondownloadlistener (Ondownloadlistener ondownloadlistener) {This.ondownloadlistener = Ondownloadlistener;} Download callback interface public interface Ondownloadlistener {public void Downloadstart (int fileSize);p ublic void downloadprogress (int downloadedsize);p ublic void Downloadend ();}}
through the external exposed interface, we can realize the download progress of monitoring!
It's easy to use, like this, OK.
String urlstring = "Http://bbra.cn/Uploadfiles/imgs/20110303/fengjin/013.jpg"; final string localPath = Environment.getexternalstoragedirectory (). GetAbsolutePath () + "/adownloadtest"; mdownloadutil = new DownloadUtil (2, LocalPath, "Abc.jpg", Urlstring,this); Mdownloadutil.setondownloadlistener (new Ondownloadlistener () {@ overridepublic void Downloadstart (int fileSize) {max = Filesize;mprogressbar.setmax (fileSize);} @Overridepublic void downloadprogress (int downloadedsize) {mprogressbar.setprogress (downloadedsize); Total.settext ( (int) downloadedsize * 100/max + "%");} @Overridepublic void Downloadend () {Bitmap Bitmap = Decodesampledbitmapfromresource (localpath+ file.separator + " Abc.jpg ", Image.setimagebitmap (bitmap);});
"Android Development experience" A simple implementation and explanation of the "multi-threaded breakpoint continuation download" feature