Detailed Android multithreaded breakpoint download _android

Source: Internet
Author: User
Tags file info xmlns

First, look at the principle of multithreaded downloads. Multi-threaded downloads are the original files on the same network according to the number of threads divided into equal, and then each individual thread to download the corresponding part, and then the download of good files in accordance with the order of the original file "stitching" up on the construction

became a complete document. This greatly improves the download efficiency of the file. For file downloads, multithreaded downloads are a must.

Multithreaded downloads can be roughly divided into the following steps:

A To get the size of the destination file on the server

Obviously this step is to access the network first, only need to get to the total size of the target file. The purpose is to calculate the download task that each thread should allocate.

Two. Create a local file of the same size as the original file

Locally you can create a file of the same size as the target file by Randomaccessfile, which supports read and write operations at any location in the file. This provides convenience for multithreaded downloads, with each thread simply writing data within the specified start and end pin range.

Three Calculate starting and ending positions for each thread download

We can take the original file as a byte array, and each thread downloads only the portion between the specified starting position of the "array" and the specified end position. In the first step we already know the total length of the "array". So as long as you know the total number of open threads to calculate the range of each thread to download.       The number of bytes (blockSize) = Total bytes (totalsize)/Thread count (threadcount) that each thread needs to download. Assuming that threads are numbered sequentially by 0,1,2,3...N, the nth thread downloads the file in the range:

The starting foot Mark Startindex=n*blocksize.

End foot Mark Endindex= (n-1) *blocksize-1.

Considering that Totalsize/threadcount is not necessarily divisible, so the last thread should be special treatment, the last thread of the start of the calculation formula is not changed, but the end of the foot marked as endindex=totalsize-1 can.

Four Open multiple child threads to start downloading

The read stream operation is implemented in the child thread, and the Conn.getinputstream () is read into the randomaccessfile.

Five Record Download Progress

Create a temporary file for each individual thread to record the progress of the thread's download. For a separate thread, each download part of the data records the number of bytes currently downloaded in the local file. In this case, if the download task terminates abnormally, the next time you restart the download, you can go back to the last progress download.

Six Delete temporary files

When multiple threads have been downloaded, the last downloaded thread deletes all of the temporary files.

Android has an interface that can interact well with the user, allowing the user to enter the original file address, number of threads, and then click OK to start downloading. In order for the user to see clearly the progress of each thread's download, an Equal progress bar (ProgressBar) is generated dynamically based on the number of threads. ProgressBar is a progress bar control that shows the progress of a task's completion. It has two styles, one is circular, which is the default for the system, because it is not possible to display specific progress values and is suitable for uncertain how long to wait; the other is a strip, which has two colors, and the highlight color represents the overall progress of the task. For our download task, because the overages (the number of bytes to download) is clear, the currently completed task (the number of bytes already downloaded) is clear, so it is particularly appropriate to use the latter. Because in our demand ProgressBar is to be added dynamically according to the number of threads, and the requirement is long. Therefore, you can write the ProgressBar style in the layout file beforehand. Fill in the layout when you need it. The ProgressBar Max property represents its maximum scale value, and the Progress property represents the current progress value. Use the following methods:

Progressbar.setmax (int max), setting the maximum scale value.

progressbar.setprogress (int progress), setting the current progress value.

Setting the maximum scale value and modifying the progress value to the ProgressBar can be manipulated in a child thread, and its interior has been specially processed, so there is no need to send a message via handler to make the main thread modify progress.

Here are some of the threads that we write in our own Android environment.

The multithreaded download interface is arranged as follows, and three progress bars represent the download progress of three child threads, respectively.

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http:// Schemas.android.com/tools "android:layout_width=" match_parent "android:layout_height=" Match_parent "Android:o" rientation= "vertical" android:paddingbottom= "@dimen/activity_vertical_margin" android:paddingleft= "@dimen Activity_horizontal_margin "android:paddingright=" @dimen/activity_horizontal_margin "android:paddingtop=" @dimen Activity_vertical_margin "tools:context=". Mainactivity "> <edittext android:id=" @+id/et_path "android:layout_width=" Match_parent "Android:layout_height"
 = "Wrap_content" android:hint= "Please enter the path to the file resource to download" android:text= "Http://192.168.1.104:8080/gg.exe"/> <button Android:layout_width= "Match_parent" android:layout_height= "wrap_content" android:onclick= "Download" android:text= "Download"/> <progressbar android:id= "@+id/pb0" style= "Android:attr/progressbarstylehorizontal" Android:layout_ Width= "Match_parent" android:layout_height= "Wrap_content"/>
 <progressbar android:id= "@+id/pb1" style=? Android:attr/progressbarstylehorizontal "Android:layout_width=" Match_parent "android:layout_height=" wrap_content "/> <progressbar android:id=" @+id/pb2 "style="? android:attr /progressbarstylehorizontal "android:layout_width=" match_parent "android:layout_height=" wrap_content "/> </
 Linearlayout>

The internal logic of the

multithreading download is as follows, but it is already in the beginning, but it is the implementation of the Code.

 public class Mainactivity extends activity {private EditText et_path;
 Private ProgressBar pb0;
 Private ProgressBar PB1;
 Private ProgressBar PB2;
 /** * Open several threads download data from the server * * public static int threadcount = 3;
 public static int runningthreadcount;
 Private String path;
 @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
 Setcontentview (R.layout.activity_main);
 Initializes the control Et_path = (edittext) Findviewbyid (R.id.et_path);
 Pb0 = (ProgressBar) Findviewbyid (r.id.pb0);
 PB1 = (ProgressBar) Findviewbyid (R.ID.PB1);
 PB2 = (ProgressBar) Findviewbyid (R.ID.PB2);
 ///Download button click event public void Download (view view) {path = Et_path.gettext (). toString (). Trim (); if (textutils.isempty (path) | | (!path.startswith ("http://"))
 {Toast.maketext (this, "Sorry path is not valid", 0). Show ();
 Return
 New Thread () {public void run () {try {//1. Gets the size of the target file on the server URL url = new URL (path);
 HttpURLConnection conn = (httpurlconnection) url.openconnection (); Conn.setconNecttimeout (5000);
 Conn.setrequestmethod ("get");
 int code = Conn.getresponsecode ();
 if (code = n) {int length = Conn.getcontentlength ();
 System.out.println ("The length of the server file is:" +); 2. Create a local file with the same size as the original file Randomaccessfile RAF = new Randomaccessfile (Environment.getexternalstoragedirectory ().
 GetAbsolutePath () + "/" +getfilename (Path), "RW");
 Raf.setlength (length);
 Raf.close ();
 3. Calculates the starting and ending position of the download for each thread int blocksize = Length/threadcount;
 Runningthreadcount = ThreadCount;
 for (int threadId = 0; threadId < threadcount; threadid++) {int startIndex = threadId * BLOCKSIZE;
 int endindex = (threadId + 1) * BLOCKSIZE-1;
 if (threadId = = (threadCount-1)) {endindex = length-1;
 //4. Open multiple child threads to start downloading new Downloadthread (ThreadId, StartIndex, Endindex). Start ();
 A catch (Exception e) {e.printstacktrace ());
 }
 };
 }.start ();
 Private class Downloadthread extends thread {/** * thread ID */private int threadId;
 /** * Thread Download theory start position * * Private int startIndex; /**
 *Thread download End position */private int endindex;
 /** * The current thread downloads to the location of the file.
 * * private int currentposition;
 Public downloadthread (int threadId, int startIndex, int endindex) {this.threadid = ThreadId;
 This.startindex = StartIndex;
 This.endindex = Endindex;
 System.out.println (threadId + "line download range is:" + StartIndex + "~ ~" + endindex);
 CurrentPosition = StartIndex;
 @Override public void Run () {try {URL url = new URL (path);
 HttpURLConnection conn = (httpurlconnection) url.openconnection (); Check that the current thread has downloaded part of the data. File info = new file (Environment.getexternalstoragedirectory (). GetAbsolutePath () + "/" +
 threadid+ ". Position"); Randomaccessfile RAF = new Randomaccessfile (Environment.getexternalstoragedirectory (). GetAbsolutePath () + "/" +
 GetFileName (Path), "RW");
 if (Info.exists () &&info.length () >0) {FileInputStream FIS = new FileInputStream (info);
 BufferedReader br = new BufferedReader (new InputStreamReader (FIS));
 CurrentPosition = integer.valueof (Br.readline ()); Conn.setrequesTproperty ("Range", "bytes=" +currentposition+ "-" +endindex);
 System.out.println ("The original download progress, from the last stop to download the position" + "bytes=" +currentposition+ "-" +endindex);
 Fis.close ();
 Raf.seek (currentposition);//The start position of each thread to write a file is different.
 }else{//Tell the server to download only a portion of the resource Conn.setrequestproperty ("Range", "bytes=" +startindex+ "-" +endindex);
 System.out.println ("There is no download progress, new download" + "bytes=" +startindex+ "-" +endindex);
 Raf.seek (StartIndex);//The start position of each thread to write a file is different.
 } InputStream is = Conn.getinputstream ();
 byte[] buffer = new byte[1024];
 int len =-1; while (len = is.read (buffer))!=-1 {//The data downloaded by each thread is placed in its own space.//System.out.println ("Thread:" +threadid+ "Downloading:" +new String (
 Buffer));
 Raf.write (buffer,0, Len);
 5. Record download Progress Currentposition+=len;
 File File = new file (Environment.getexternalstoragedirectory (). GetAbsolutePath () + "/" +threadid+ ". Position");
 Randomaccessfile fos = new Randomaccessfile (file, "RWD");
 System.out.println ("Thread:" +threadid+ "wrote" +currentposition);
 Fos.write (String.valueof (currentposition). GetBytes ()); Fos.close ()//Fileoutstream data is not necessarily written to the underlying device, it may be stored in the cache.
 RAF's RWD mode, the data is immediately stored in the underlying hard disk device.
 Update the display of the progress bar int max = Endindex-startindex;
 int progress = Currentposition-startindex;
 if (threadid==0) {Pb0.setmax (max);
 Pb0.setprogress (progress);
 }else if (threadid==1) {Pb1.setmax (max);
 Pb1.setprogress (progress);
 }else if (threadid==2) {Pb2.setmax (max);
 Pb2.setprogress (progress);
 } raf.close ();
 Is.close ();
 System.out.println ("Thread:" +threadid+ "Download completed ...");
 File F = new file (Environment.getexternalstoragedirectory (). GetAbsolutePath () + "/" +threadid+ ". Position"); F.renameto (New File (Environment.getexternalstoragedirectory (). GetAbsolutePath () + "/" +threadid+ ". Position.finish"
 ));
 Synchronized (mainactivity.class) {runningthreadcount--; 6. Delete temporary file if (runningthreadcount<=0) {for (int i=0;i<threadcount;i++) {File ft = new file (environment.getexternal
 Storagedirectory (). GetAbsolutePath () + "/" +i+ ". Position.finish");
 Ft.delete ();
 catch (Exception e) {e.printstacktrace ()}}};
 }
 }/** * Get a file name * @param path * @return/Public String GetFileName (string path) {int start = Path.lastindexof ("/
 ") +1;
 Return path.substring (start);
 }
}

Finally, do not forget to add permissions, in this project not only use network access also use SDcard storage, so you need to add two permissions.

<uses-permission android:name= "Android.permission.INTERNET"/>
<uses-permission android:name= " Android.permission.WRITE_EXTERNAL_STORAGE "/>

In addition, Xutils can also implement multithreaded downloads. Xutils is open source free Android toolkit, code hosted on GitHub. At present, Xutils mainly has four modules: Dbutils module, which is mainly used in the framework of operation database. Viewutils module, which enables you to manage UI, resource, and event bindings through annotations. Httputils module, provides convenient network access, breakpoint extension and other functions. The Bitmaputils module provides powerful image processing tools. We are here only simple practical xutils tools in the Httputils tool. Third-party packages are simpler to use, directly copy xutils jar packages into the Libs directory, and then add dependencies.

You can then use the features of the httputils in Xutils:

Httputils http = new Httputils ();
 /**
 * Parameter 1: Original file network address
 * Parameter 2: Locally saved address
 * Parameter 3: Support breakpoint Continuation, true: Support, false:
 * Parameter 4: Callback interface, the method in this interface is called in the main thread,
 * That is, the method in this interface can modify the UI
 /http.download (path, "/mnt/sdcard/xxx.exe", true, new Requestcallback<file > () {
 ////After successful download
 @Override public
 void onsuccess (responseinfo<file> arg0) {
 Toast.maketext (Mainactivity.this, "Download Successful", 0). Show ();
 /**
 * Every download part is called once, through this method can know the current download Progress
 * Parameter 1: Total bytes of the original file
 * Parameter 2: The number of bytes currently downloaded
 * Parameter 3: Whether upload, for download, this value is False
 */
 @Override public
 void onloading (Long, Long, Boolean isuploading) {
 Pb0.setmax ( int) total);
 Pb0.setprogress ((int) current);
 Super.onloading (total, Current, isuploading);
 }
 Once
 a failure is invoked @Override public
 void OnFailure (HttpException arg0, String arg1) {
 Toast.maketext ( Mainactivity.this, "Download Failed" +arg1, 0). Show (();
 }
 });

The above is the entire content of this article, I hope the content of this article for everyone's study or work can bring some help, but also hope that a lot of support cloud Habitat community!

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.