Android进阶:实现多线程下载文件

    xiaoxiao2021-12-14  18

    多线程下载大概思路就是通过Range 属性实现文件分段,然后用RandomAccessFile 来读写文件,最终合并为一个文件

     

    首先看下效果图

     

     

    创建工程 ThreadDemo

     

    首先布局文件 threaddemo.xml

     

    view plain copy to clipboard print ? <?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:orientation="vertical"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      >  <TextView        android:layout_width="fill_parent"       android:layout_height="wrap_content"       android:text="下载地址"      />  <TextView      android:id="@+id/downloadurl"      android:layout_width="fill_parent"       android:layout_height="wrap_content"       android:lines="5"      />  <TextView        android:layout_width="fill_parent"       android:layout_height="wrap_content"       android:text="线程数"      />  <EditText      android:id="@+id/downloadnum"      android:layout_width="fill_parent"       android:layout_height="wrap_content"       />  <ProgressBar      android:id="@+id/downloadProgressBar"      android:layout_width="fill_parent"       style="?android:attr/progressBarStyleHorizontal"      android:layout_height="wrap_content"       />  <TextView      android:id="@+id/downloadinfo"      android:layout_width="fill_parent"       android:layout_height="wrap_content"       android:text="下载进度 0"      />  <Button      android:id="@+id/downloadbutton"      android:layout_width="wrap_content"       android:layout_height="wrap_content"       android:text="开始下载"      />  </LinearLayout>   [c-sharp] view plain copy print ? <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><TextView      android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:text="下载地址"    /><TextViewandroid:id="@+id/downloadurl"android:layout_width="fill_parent"     android:layout_height="wrap_content" android:lines="5"/><TextView      android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:text="线程数"    /><EditTextandroid:id="@+id/downloadnum"android:layout_width="fill_parent"     android:layout_height="wrap_content" /><ProgressBarandroid:id="@+id/downloadProgressBar"android:layout_width="fill_parent" style="?android:attr/progressBarStyleHorizontal"    android:layout_height="wrap_content" /><TextViewandroid:id="@+id/downloadinfo"android:layout_width="fill_parent"     android:layout_height="wrap_content"     android:text="下载进度 0"/><Buttonandroid:id="@+id/downloadbutton"android:layout_width="wrap_content"     android:layout_height="wrap_content"     android:text="开始下载"/></LinearLayout>   <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" ><TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下载地址" /><TextViewandroid:id="@+id/downloadurl"android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="5"/><TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="线程数" /><EditTextandroid:id="@+id/downloadnum"android:layout_width="fill_parent" android:layout_height="wrap_content" /><ProgressBarandroid:id="@+id/downloadProgressBar"android:layout_width="fill_parent" style="?android:attr/progressBarStyleHorizontal" android:layout_height="wrap_content" /><TextViewandroid:id="@+id/downloadinfo"android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下载进度 0"/><Buttonandroid:id="@+id/downloadbutton"android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始下载"/></LinearLayout>

     

    主界面 Acitivity

     

    view plain copy to clipboard print ? public class ThreadDownloadDemo extends Activity {         private TextView downloadurl;      private EditText downloadnum;      private Button downloadbutton;      private ProgressBar downloadProgressBar;      private TextView downloadinfo;      private int downloadedSize = 0;      private int fileSize = 0;            private long downloadtime;         @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.threaddemo);             downloadurl = (TextView) findViewById(R.id.downloadurl);          downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/荷塘月色.mp3");          downloadnum = (EditText) findViewById(R.id.downloadnum);          downloadinfo = (TextView) findViewById(R.id.downloadinfo);          downloadbutton = (Button) findViewById(R.id.downloadbutton);          downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);          downloadProgressBar.setVisibility(View.VISIBLE);          downloadProgressBar.setMax(100);          downloadProgressBar.setProgress(0);          downloadbutton.setOnClickListener(new OnClickListener() {              public void onClick(View v) {                  download();                  downloadtime = SystemClock.currentThreadTimeMillis();              }          });      }         private void download() {          // 获取SD卡目录           String dowloadDir = Environment.getExternalStorageDirectory()                  + "/threaddemodownload/";          File file = new File(dowloadDir);          //创建下载目录           if (!file.exists()) {              file.mkdirs();          }                    //读取下载线程数,如果为空,则单线程下载           int downloadTN = Integer.valueOf("".equals(downloadnum.getText()                  .toString()) ? "1" : downloadnum.getText().toString());          String fileName = "hetang.mp3";          //开始下载前把下载按钮设置为不可用           downloadbutton.setClickable(false);          //进度条设为0           downloadProgressBar.setProgress(0);          //启动文件下载线程           new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/荷塘月色.mp3", Integer                  .valueOf(downloadTN), dowloadDir + fileName).start();      }         Handler handler = new Handler() {          @Override          public void handleMessage(Message msg) {              //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息               int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();              if (progress == 100) {                  downloadbutton.setClickable(true);                  downloadinfo.setText("下载完成!");                  Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this)                      .setTitle("提示信息")                      .setMessage("下载完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒")                      .setNegativeButton("确定"new DialogInterface.OnClickListener(){                          @Override                          public void onClick(DialogInterface dialog, int which) {                              dialog.dismiss();                          }                      })                      .create();                  mdialog.show();              } else {                  downloadinfo.setText("当前进度:" + progress + "%");              }              downloadProgressBar.setProgress(progress);          }         };               public class downloadTask extends Thread {          private int blockSize, downloadSizeMore;          private int threadNum = 5;          String urlStr, threadNo, fileName;             public downloadTask(String urlStr, int threadNum, String fileName) {              this.urlStr = urlStr;              this.threadNum = threadNum;              this.fileName = fileName;          }             @Override          public void run() {              FileDownloadThread[] fds = new FileDownloadThread[threadNum];              try {                  URL url = new URL(urlStr);                  URLConnection conn = url.openConnection();                  //防止返回-1                   InputStream in = conn.getInputStream();                  //获取下载文件的总大小                   fileSize = conn.getContentLength();                  Log.i("bb""======================fileSize:"+fileSize);                  //计算每个线程要下载的数据量                   blockSize = fileSize / threadNum;                  // 解决整除后百分比计算误差                   downloadSizeMore = (fileSize % threadNum);                  File file = new File(fileName);                  for (int i = 0; i < threadNum; i++) {                      Log.i("bb""======================i:"+i);                      //启动线程,分别下载自己需要下载的部分                       FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);                      fdt.setName("Thread" + i);                      fdt.start();                      fds[i] = fdt;                  }                  boolean finished = false;                  while (!finished) {                      // 先把整除的余数搞定                       downloadedSize = downloadSizeMore;                      finished = true;                      for (int i = 0; i < fds.length; i++) {                          downloadedSize += fds[i].getDownloadSize();                          if (!fds[i].isFinished()) {                              finished = false;                          }                      }                      handler.sendEmptyMessage(0);                      //线程暂停一秒                       sleep(1000);                  }              } catch (Exception e) {                  e.printStackTrace();              }             }      }  }   [c-sharp] view plain copy print ? public class ThreadDownloadDemo extends Activity { private TextView downloadurl;private EditText downloadnum;private Button downloadbutton;private ProgressBar downloadProgressBar;private TextView downloadinfo;private int downloadedSize = 0;private int fileSize = 0;private long downloadtime; @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.threaddemo); downloadurl = (TextView) findViewById(R.id.downloadurl);downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/荷塘月色.mp3");downloadnum = (EditText) findViewById(R.id.downloadnum);downloadinfo = (TextView) findViewById(R.id.downloadinfo);downloadbutton = (Button) findViewById(R.id.downloadbutton);downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);downloadProgressBar.setVisibility(View.VISIBLE);downloadProgressBar.setMax(100);downloadProgressBar.setProgress(0);downloadbutton.setOnClickListener(new OnClickListener() {public void onClick(View v) {download();downloadtime = SystemClock.currentThreadTimeMillis();}});} private void download() {// 获取SD卡目录String dowloadDir = Environment.getExternalStorageDirectory()+ "/threaddemodownload/";File file = new File(dowloadDir);//创建下载目录if (!file.exists()) {file.mkdirs();}//读取下载线程数,如果为空,则单线程下载int downloadTN = Integer.valueOf("".equals(downloadnum.getText().toString()) ? "1" : downloadnum.getText().toString());String fileName = "hetang.mp3";//开始下载前把下载按钮设置为不可用downloadbutton.setClickable(false);//进度条设为0downloadProgressBar.setProgress(0);//启动文件下载线程new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/荷塘月色.mp3", Integer.valueOf(downloadTN), dowloadDir + fileName).start();} Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {//当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();if (progress == 100) {downloadbutton.setClickable(true);downloadinfo.setText("下载完成!");Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this).setTitle("提示信息").setMessage("下载完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒").setNegativeButton("确定"new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}}).create();mdialog.show();} else {downloadinfo.setText("当前进度:" + progress + "%");}downloadProgressBar.setProgress(progress);} }; public class downloadTask extends Thread {private int blockSize, downloadSizeMore;private int threadNum = 5;String urlStr, threadNo, fileName; public downloadTask(String urlStr, int threadNum, String fileName) {this.urlStr = urlStr;this.threadNum = threadNum;this.fileName = fileName;} @Overridepublic void run() {FileDownloadThread[] fds = new FileDownloadThread[threadNum];try {URL url = new URL(urlStr);URLConnection conn = url.openConnection();//防止返回-1InputStream in = conn.getInputStream();//获取下载文件的总大小fileSize = conn.getContentLength();Log.i("bb""======================fileSize:"+fileSize);//计算每个线程要下载的数据量blockSize = fileSize / threadNum;// 解决整除后百分比计算误差downloadSizeMore = (fileSize % threadNum);File file = new File(fileName);for (int i = 0; i < threadNum; i++) {Log.i("bb""======================i:"+i);//启动线程,分别下载自己需要下载的部分FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);fdt.setName("Thread" + i);fdt.start();fds[i] = fdt;}boolean finished = false;while (!finished) {// 先把整除的余数搞定downloadedSize = downloadSizeMore;finished = true;for (int i = 0; i < fds.length; i++) {downloadedSize += fds[i].getDownloadSize();if (!fds[i].isFinished()) {finished = false;}}handler.sendEmptyMessage(0);//线程暂停一秒sleep(1000);}} catch (Exception e) {e.printStackTrace();} }}}   public class ThreadDownloadDemo extends Activity { private TextView downloadurl;private EditText downloadnum;private Button downloadbutton;private ProgressBar downloadProgressBar;private TextView downloadinfo;private int downloadedSize = 0;private int fileSize = 0;private long downloadtime; @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.threaddemo); downloadurl = (TextView) findViewById(R.id.downloadurl);downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/荷塘月色.mp3");downloadnum = (EditText) findViewById(R.id.downloadnum);downloadinfo = (TextView) findViewById(R.id.downloadinfo);downloadbutton = (Button) findViewById(R.id.downloadbutton);downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);downloadProgressBar.setVisibility(View.VISIBLE);downloadProgressBar.setMax(100);downloadProgressBar.setProgress(0);downloadbutton.setOnClickListener(new OnClickListener() {public void onClick(View v) {download();downloadtime = SystemClock.currentThreadTimeMillis();}});} private void download() {// 获取SD卡目录String dowloadDir = Environment.getExternalStorageDirectory()+ "/threaddemodownload/";File file = new File(dowloadDir);//创建下载目录if (!file.exists()) {file.mkdirs();}//读取下载线程数,如果为空,则单线程下载int downloadTN = Integer.valueOf("".equals(downloadnum.getText().toString()) ? "1" : downloadnum.getText().toString());String fileName = "hetang.mp3";//开始下载前把下载按钮设置为不可用downloadbutton.setClickable(false);//进度条设为0downloadProgressBar.setProgress(0);//启动文件下载线程new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/荷塘月色.mp3", Integer.valueOf(downloadTN), dowloadDir + fileName).start();} Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {//当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();if (progress == 100) {downloadbutton.setClickable(true);downloadinfo.setText("下载完成!");Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this).setTitle("提示信息").setMessage("下载完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒").setNegativeButton("确定", new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss();}}).create();mdialog.show();} else {downloadinfo.setText("当前进度:" + progress + "%");}downloadProgressBar.setProgress(progress);} }; public class downloadTask extends Thread {private int blockSize, downloadSizeMore;private int threadNum = 5;String urlStr, threadNo, fileName; public downloadTask(String urlStr, int threadNum, String fileName) {this.urlStr = urlStr;this.threadNum = threadNum;this.fileName = fileName;} @Overridepublic void run() {FileDownloadThread[] fds = new FileDownloadThread[threadNum];try {URL url = new URL(urlStr);URLConnection conn = url.openConnection();//防止返回-1InputStream in = conn.getInputStream();//获取下载文件的总大小fileSize = conn.getContentLength();Log.i("bb", "======================fileSize:"+fileSize);//计算每个线程要下载的数据量blockSize = fileSize / threadNum;// 解决整除后百分比计算误差downloadSizeMore = (fileSize % threadNum);File file = new File(fileName);for (int i = 0; i < threadNum; i++) {Log.i("bb", "======================i:"+i);//启动线程,分别下载自己需要下载的部分FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);fdt.setName("Thread" + i);fdt.start();fds[i] = fdt;}boolean finished = false;while (!finished) {// 先把整除的余数搞定downloadedSize = downloadSizeMore;finished = true;for (int i = 0; i < fds.length; i++) {downloadedSize += fds[i].getDownloadSize();if (!fds[i].isFinished()) {finished = false;}}handler.sendEmptyMessage(0);//线程暂停一秒sleep(1000);}} catch (Exception e) {e.printStackTrace();} }}}

     

    这里启动线程将文件分割为几个部分,每一个部分再启动一个线程去下载数据

     

    下载文件的线程

     

    view plain copy to clipboard print ? public class FileDownloadThread extends Thread{      private static final int BUFFER_SIZE=1024;      private URL url;      private File file;      private int startPosition;      private int endPosition;      private int curPosition;      //标识当前线程是否下载完成       private boolean finished=false;      private int downloadSize=0;      public FileDownloadThread(URL url,File file,int startPosition,int endPosition){          this.url=url;          this.file=file;          this.startPosition=startPosition;          this.curPosition=startPosition;          this.endPosition=endPosition;      }      @Override      public void run() {          BufferedInputStream bis = null;          RandomAccessFile fos = null;                                                         byte[] buf = new byte[BUFFER_SIZE];          URLConnection con = null;          try {              con = url.openConnection();              con.setAllowUserInteraction(true);              //设置当前线程下载的起止点               con.setRequestProperty("Range""bytes=" + startPosition + "-" + endPosition);              Log.i("bb", Thread.currentThread().getName()+"  bytes=" + startPosition + "-" + endPosition);              //使用java中的RandomAccessFile 对文件进行随机读写操作               fos = new RandomAccessFile(file, "rw");              //设置写文件的起始位置               fos.seek(startPosition);              bis = new BufferedInputStream(con.getInputStream());                //开始循环以流的形式读写文件               while (curPosition < endPosition) {                  int len = bis.read(buf, 0, BUFFER_SIZE);                                  if (len == -1) {                      break;                  }                  fos.write(buf, 0, len);                  curPosition = curPosition + len;                  if (curPosition > endPosition) {                      downloadSize+=len - (curPosition - endPosition) + 1;                  } else {                      downloadSize+=len;                  }              }              //下载完成设为true               this.finished = true;              bis.close();              fos.close();          } catch (IOException e) {              e.printStackTrace();          }      }         public boolean isFinished(){          return finished;      }         public int getDownloadSize() {          return downloadSize;      }  }   [c-sharp] view plain copy print ? public class FileDownloadThread extends Thread{private static final int BUFFER_SIZE=1024;private URL url;private File file;private int startPosition;private int endPosition;private int curPosition;//标识当前线程是否下载完成private boolean finished=false;private int downloadSize=0;public FileDownloadThread(URL url,File file,int startPosition,int endPosition){this.url=url;this.file=file;this.startPosition=startPosition;this.curPosition=startPosition;this.endPosition=endPosition;}@Overridepublic void run() {        BufferedInputStream bis = null;        RandomAccessFile fos = null;                                                       byte[] buf = new byte[BUFFER_SIZE];        URLConnection con = null;        try {            con = url.openConnection();            con.setAllowUserInteraction(true);            //设置当前线程下载的起止点            con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition);            Log.i("bb", Thread.currentThread().getName()+"  bytes=" + startPosition + "-" + endPosition);            //使用java中的RandomAccessFile 对文件进行随机读写操作            fos = new RandomAccessFile(file, "rw");            //设置写文件的起始位置            fos.seek(startPosition);            bis = new BufferedInputStream(con.getInputStream());              //开始循环以流的形式读写文件            while (curPosition < endPosition) {                int len = bis.read(buf, 0, BUFFER_SIZE);                                if (len == -1) {                    break;                }                fos.write(buf, 0, len);                curPosition = curPosition + len;                if (curPosition > endPosition) {                    downloadSize+=len - (curPosition - endPosition) + 1;                } else {                    downloadSize+=len;                }            }            //下载完成设为true            this.finished = true;            bis.close();            fos.close();        } catch (IOException e) {          e.printStackTrace();        }} public boolean isFinished(){return finished;} public int getDownloadSize() {return downloadSize;}}   public class FileDownloadThread extends Thread{private static final int BUFFER_SIZE=1024;private URL url;private File file;private int startPosition;private int endPosition;private int curPosition;//标识当前线程是否下载完成private boolean finished=false;private int downloadSize=0;public FileDownloadThread(URL url,File file,int startPosition,int endPosition){this.url=url;this.file=file;this.startPosition=startPosition;this.curPosition=startPosition;this.endPosition=endPosition;}@Overridepublic void run() { BufferedInputStream bis = null; RandomAccessFile fos = null; byte[] buf = new byte[BUFFER_SIZE]; URLConnection con = null; try { con = url.openConnection(); con.setAllowUserInteraction(true); //设置当前线程下载的起止点 con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition); Log.i("bb", Thread.currentThread().getName()+" bytes=" + startPosition + "-" + endPosition); //使用java中的RandomAccessFile 对文件进行随机读写操作 fos = new RandomAccessFile(file, "rw"); //设置写文件的起始位置 fos.seek(startPosition); bis = new BufferedInputStream(con.getInputStream()); //开始循环以流的形式读写文件 while (curPosition < endPosition) { int len = bis.read(buf, 0, BUFFER_SIZE); if (len == -1) { break; } fos.write(buf, 0, len); curPosition = curPosition + len; if (curPosition > endPosition) { downloadSize+=len - (curPosition - endPosition) + 1; } else { downloadSize+=len; } } //下载完成设为true this.finished = true; bis.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); }} public boolean isFinished(){return finished;} public int getDownloadSize() {return downloadSize;}}

     

    这里通过RandomAccessFile 的seek方法定位到相应的位置 并实时记录下载量

     

    当然这里需要联网和访问SD卡 所以要加上相应的权限

     

    <uses-permission android:name="android.permission.INTERNET" />       <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>   [c-sharp] view plain copy print ? <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>   <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

     

    这样就OK了 下面可以看看断点续传的问题了。有待测试~~

    转载请注明原文地址: https://ju.6miu.com/read-963646.html

    最新回复(0)