Android file download (1)

Introduction to this section:

Another deep pit, beginners should be careful... This section will start from ordinary single-threaded download -> ordinary multi-threaded download -> -> and a very practical example: use Android's DownloadManager to update apk and overwrite the installed one Implement the code! Ok, so it looks like this section is quite interesting, let's start this section! PS: We put the entire complete multi-threaded breakpoint resume in the next section!


1. Ordinary single-thread download file:

Directly use URLConnection.openStream() to open the network input stream, and then write the stream to the file!

Core method :

public static void downLoad(String path,Context context)throws Exception
{
  URL url = new URL(path);
  InputStream is = url.openStream();
  //Intercept the last file name
  String end = path.substring(path.lastIndexOf("."));
  //Open the output stream corresponding to the mobile phone and output it to the file
  OutputStream os = context.openFileOutput("Cache_"+System.currentTimeMillis()+end, Context.MODE_PRIVATE);
  byte[] buffer = new byte[1024];
  int len = 0;
  //Read data from input six and read it into the buffer
  while((len = is.read(buffer)) > 0)
  {
    os.write(buffer,0,len);
  }
  //Close the input and output stream
  is.close();
  os.close();
}

Running result :


2. Ordinary multi-threaded download:

We all know that downloading files using multiple threads can complete the file download faster, but why?

Answer: Because there are many server resources preempted, assuming that the server can serve up to 100 users, one thread in the server corresponds to one user. 100 threads are executed concurrently in the computer, and the CPU divides the time slices to execute in turn. Add a and there are 99 threads to download files. , then it is equivalent to occupying 99 user resources, and naturally has a faster download speed

PS : Of course, the more threads, the better. If you open too many threads, the app needs to maintain and synchronize the overhead of each thread. These overheads will actually reduce the download speed, and it is also related to your network speed!

The process of multi-threaded download :

  • get internet connection
  • local disk creates empty files of the same size
  • Calculate from which part of the file each thread needs to start downloading and end
  • Create in turn, start multiple threads to download the specified part of the network resource

PS: Create a Java project directly here, and then run the specified method in JUnit,

The core code is as follows :

public class Downloader {
  // Adding the @Test tag means that the method is a Junit test method, and you can run the method directly
    @Test
    public void download() throws Exception
    {
      //Set URL address and downloaded file name
      String filename = "meitu.exe";
      String path = "http://10.13.20.32:8080/Test/XiuXiu_Green.exe";
      URL url = new URL(path);
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
      conn.setConnectTimeout(5000);
      conn.setRequestMethod("GET");
      //Get the length (size) of the file to be downloaded
      int filelength = conn.getContentLength();
      System.out.println("The length of the file to be downloaded"+filelength);
      //Generate a local file of the same size
      RandomAccessFile file = new RandomAccessFile(filename, "rwd");
      file.setLength(filelength);
      file.close();
      conn.disconnect();
      //Set how many threads to download
      int threadsize = 3;
      //Calculate the amount downloaded by each thread
      int threadlength = filelength % 3 == 0 ? filelength/3:filelength+1;
      for(int i = 0;i < threadsize;i++)
      {
        //Set where each thread starts downloading
        int startposition = i * threadlength;
        //Where to start writing data from the file
        RandomAccessFile threadfile = new RandomAccessFile(filename, "rwd");
        threadfile.seek(startposition);
        //Start three threads to start downloading files from the startposition position respectively
        new DownLoadThread(i,startposition,threadfile,threadlength,path).start();
      }
      int quit = System.in.read();
      while('q' != quit)
      {
        Thread.sleep(2000);
      }
    }
  
  
  private class DownLoadThread extends Thread {
    private int threadid;
    private int startposition;
    private RandomAccessFile threadfile;
    private int threadlength;
    private String path;
    public DownLoadThread(int threadid, int startposition,
        RandomAccessFile threadfile, int threadlength, String path) {
      this.threadid = threadid;
      this.startposition = startposition;
      this.threadfile = threadfile;
      this.threadlength = threadlength;
      this.path = path;
    }
    public DownLoadThread() {}
    @Override
    public void run() {
      try
      {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(5000);
        conn.setRequestMethod("GET");
        //Specify where to start downloading
        conn.setRequestProperty("Range", "bytes="+startposition+"-");
        //System.out.println(conn.getResponseCode());
        if(conn.getResponseCode() == 206)
        {
          InputStream is = conn.getInputStream();
          byte[] buffer = new byte[1024];
          int len = -1;
          int length = 0;
          while(length < threadlength && (len = is.read(buffer)) != -1)
          {
            threadfile.write(buffer,0,len);
            //Calculate the length of the cumulative download
            length += len;
          }
          threadfile.close();
          is.close();
          System.out.println("Thread"+(threadid+1) + "Downloaded");
        }
      }catch(Exception ex){System.out.println("thread"+(threadid+1) + "download error"+ ex);}
    }
    
  }
}

Run the screenshot:

As shown in the figure, the download of the file is completed using multi-threading! Double-click the exe file to run it, indicating that the file is not damaged!

Precautions:

  • int filelength = conn.getContentLength(); //Get the length (size) of the downloaded file
  • RandomAccessFile file = new RandomAccessFile(filename, "rwd"); //This class runs to read and write files, which is the core of multi-thread download
  • nt threadlength = filelength % 3 == 0 ? filelength/3:filelength+1; // Calculate the amount to be downloaded by each thread
  • conn.setRequestProperty("Range", "bytes="+startposition+"-"); //Specify where to start reading and writing, this is the method provided by URLConnection
  • //System.out.println(conn.getResponseCode()); //This annotated code is used to view the return code of conn. We used 200 before, but for multi-threading, it is usually 206. We can check the return code by calling this method if necessary!
  • int quit = System.in.read(); while('q' != quit){Thread.sleep(2000);} //This code is for delay operation, because we use local download, maybe This method has finished running, and our thread has not been opened, which will cause an exception. Here, let the user enter a character, and exit if it is'q'

3. Use DownloadManager to update the application and overwrite the installation:

The following code can be used directly. After adding it to the project, remember to register a filter for this internal broadcast:

AndroidManifest.xml

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;

/**
 * Created by Jay on 2015/9/9 0009.
 */
public class UpdateAct extends AppCompatActivity {
    //The version part of this updated APK, we named it like this: xxx_v1.0.0_xxxxxxxxx.apk
    //Here we use the first nine digits of the git submission version as a representation
    private static final String FILE_NAME = "ABCDEFGHI";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String endpoint = "";
        try {
            //This part is to get the configuration information in AndroidManifest.xml, the package name, and the things saved in Meta_data
            ApplicationInfo info = getPackageManager().getApplicationInfo(
                    getPackageName(), PackageManager.GET_META_DATA);
            //We saved data like xxx.xxx in meta_data, which is a link at the beginning of https, here it is replaced by http
            endpoint = info.metaData.getString("xxxx.xxxx").replace("https",
                    "http");
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        //The following are spliced ​​apk update download urls, path is the saved folder path
        final String _Path = this.getIntent().getStringExtra("path");
        final String _Url = endpoint + _Path;
        final DownloadManager _DownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        DownloadManager.Request _Request = new DownloadManager.Request(
                Uri.parse(_Url));
        _Request.setDestinationInExternalPublicDir(
                Environment.DIRECTORY_DOWNLOADS, FILE_NAME + ".apk");
        _Request.setTitle(this.getString(R.string.app_name));
        //Whether to show the download dialog
        _Request.setShowRunningNotification(true);
        _Request.setMimeType("application/com.trinea.download.file");
        // Put the download request into the queue
        _DownloadManager.enqueue(_Request);
        this.finish();
    }



    //Register a broadcast receiver, when the download is complete, you will receive an android.intent.action.DOWNLOAD_COMPLETE
    //Broadcast, take out the download task in the queue here, and install it
    public static class Receiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            final DownloadManager _DownloadManager = (DownloadManager) context
                    .getSystemService(Context.DOWNLOAD_SERVICE);
            final long _DownloadId = intent.getLongExtra(
                    DownloadManager.EXTRA_DOWNLOAD_ID, 0);
            final DownloadManager.Query _Query = new DownloadManager.Query();
            _Query.setFilterById(_DownloadId);
            final Cursor _Cursor = _DownloadManager.query(_Query);
            if (_Cursor.moveToFirst()) {
                final int _Status = _Cursor.getInt(_Cursor
                        .getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
                final String _Name = _Cursor.getString(_Cursor
                        .getColumnIndexOrThrow("local_filename"));
                if (_Status == DownloadManager.STATUS_SUCCESSFUL
                        && _Name.indexOf(FILE_NAME) != 0) {

                    Intent _Intent = new Intent(Intent.ACTION_VIEW);
                    _Intent.setDataAndType(
                            Uri.parse(_Cursor.getString(_Cursor
                                    .getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI))),
                            "application/vnd.android.package-archive");
                    _Intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(_Intent);
                }
            }
            _Cursor.close();
        }
    }
}

Guess you like

Origin blog.csdn.net/leyang0910/article/details/131475675