安卓 下载多线程带进度条

当我们学完java中多线程的下载后,能够将它移植到我们的安卓中来。以下是详细实现源代码:

DownActivity.java

[java] view plaincopy
  1. package com.example.downloads;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.RandomAccessFile;  
  6. import java.net.HttpURLConnection;  
  7. import java.net.MalformedURLException;  
  8. import java.net.URL;  
  9. import com.example.downloads.utils.DownLoadThread;  
  10. import android.os.Bundle;  
  11. import android.os.Environment;  
  12. import android.os.Handler;  
  13. import android.os.Message;  
  14. import android.annotation.SuppressLint;  
  15. import android.app.Activity;  
  16. import android.text.TextUtils;  
  17. import android.view.Menu;  
  18. import android.view.View;  
  19. import android.widget.EditText;  
  20. import android.widget.ProgressBar;  
  21. import android.widget.TextView;  
  22. import android.widget.Toast;  
  23.   
  24. public class DownActivity extends Activity {  
  25.     // 声明控件  
  26.     // 路径与线程数量  
  27.     public EditText et_url, et_num;  
  28.     // 进度条  
  29.     public static ProgressBar pb_thread;  
  30.     // 显示运行进度的操作  
  31.     public TextView tv_pb;  
  32.     // 线程的数量  
  33.     public static int threadNum = 3;  
  34.     // 每一个线程负责下载的大小  
  35.     public int blockSize;  
  36.     public static int threadCount;// 数量  
  37.     // 訪问的path  
  38.     public String path;  
  39.     public static boolean flag = true;  
  40.     // 记录进度条的值  
  41.     public static int pb_count = 0;  
  42.     public static Handler handler;  
  43.     public static final int TEXTVALUE = 1;  
  44.     public static int pb_num = 0;  
  45.     public static int size = 0;  
  46.   
  47.     @Override  
  48.     protected void onCreate(Bundle savedInstanceState) {  
  49.         super.onCreate(savedInstanceState);  
  50.         setContentView(R.layout.activity_down);  
  51.         et_url = (EditText) findViewById(R.id.et_path);  
  52.         et_num = (EditText) findViewById(R.id.et_threadNum);  
  53.         pb_thread = (ProgressBar) findViewById(R.id.pb_down);  
  54.         tv_pb = (TextView) findViewById(R.id.tv_pb);  
  55.         handler = new Handler() {  
  56.             @SuppressLint("HandlerLeak")  
  57.             @Override  
  58.             public void handleMessage(Message msg) {  
  59.                 super.handleMessage(msg);  
  60.                 switch (msg.what) {  
  61.                 case TEXTVALUE:  
  62.                     System.out.println("-------" + DownActivity.pb_count  
  63.                             + "//////" + DownActivity.size);  
  64.                     // 改变TEXTView  
  65.                     pb_num = (DownActivity.pb_count * 100) / DownActivity.size;  
  66.                     tv_pb.setText("当前进度是+" + pb_num + "%");  
  67.                       
  68.                     break;  
  69.   
  70.                 default:  
  71.                     break;  
  72.                 }  
  73.             }  
  74.   
  75.         };  
  76.   
  77.     }  
  78.   
  79.     @Override  
  80.     public boolean onCreateOptionsMenu(Menu menu) {  
  81.         // Inflate the menu; this adds items to the action bar if it is present.  
  82.         getMenuInflater().inflate(R.menu.main, menu);  
  83.         return true;  
  84.     }  
  85.   
  86.     public void downLoad(View v) {  
  87.         DownActivity.flag = true;  
  88.         DownActivity.pb_count = 0;  
  89.   
  90.         path = et_url.getText().toString();  
  91.         String threadNum_et = et_num.getText().toString();  
  92.   
  93.         if (TextUtils.isEmpty(path) || TextUtils.isEmpty(threadNum_et)) {  
  94.             Toast.makeText(this"不能为空", Toast.LENGTH_LONG).show();  
  95.             return;  
  96.         }  
  97.         Toast.makeText(this"url:" + path + "--" + threadNum_et,  
  98.                 Toast.LENGTH_LONG).show();  
  99.         // 转换成数字  
  100.         threadNum = Integer.valueOf(threadNum_et);  
  101.         new Thread(new Runnable() {  
  102.             @Override  
  103.             public void run() {  
  104.                 try {  
  105.                     // 创建出URL对象  
  106.                     URL url = new URL(path);  
  107.                     // 创建出 HttpURLConnection对象  
  108.                     HttpURLConnection httpURLConnection = (HttpURLConnection) url  
  109.                             .openConnection();  
  110.   
  111.                     // 设置 发请求发送的方式  
  112.                     httpURLConnection.setRequestMethod("GET");  
  113.                     // 设置请求是否超时时间  
  114.                     httpURLConnection.setConnectTimeout(5000);  
  115.                     // 设置  
  116.                     httpURLConnection  
  117.                             .setRequestProperty("User-Agent",  
  118.                                     " Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)");  
  119.   
  120.                     // 是否响应成功  
  121.                     if (httpURLConnection.getResponseCode() == 200) {  
  122.                         // 获取文件的大小  
  123.                         size = httpURLConnection.getContentLength();  
  124.                         System.out.println("文件的大小" + size);  
  125.                         // 设置进度条的最大值  
  126.                         pb_thread.setMax(size);  
  127.   
  128.                         // 创建文件 //保存到SD卡上  
  129.   
  130.                         // 首先推断是否拥有sdcard  
  131.                         if (Environment.getExternalStorageState().equals(  
  132.                                 Environment.MEDIA_MOUNTED)) {  
  133.                             // 获取sdCard文件文件夹对象  
  134.                             File sdFile = Environment  
  135.                                     .getExternalStorageDirectory();  
  136.                             // 创建文件对象  
  137.                             File file = new File(sdFile, "youdao.exe");  
  138.   
  139.                             RandomAccessFile accessFile = new RandomAccessFile(  
  140.                                     file, "rwd");  
  141.                             // 设置文件的大小  
  142.                             accessFile.setLength(size);  
  143.                             // 每一个线程下载的大小  
  144.                             blockSize = size / threadNum;  
  145.                             // 开三个线程 操作此文件  
  146.                             for (int i = 1; i <= threadNum; i++) {  
  147.                                 // 1 2 3  
  148.                                 // 计算出每一个线程開始的位置  
  149.                                 int startSize = (i - 1) * blockSize;  
  150.                                 // 结束位置  
  151.                                 int endSize = (i) * blockSize;  
  152.                                 // 当线程是最后一个线程的时候  
  153.                                 if (i == threadNum) {  
  154.                                     // 推断文件的大小是否大于计算出来的结束位置  
  155.                                     if (size > endSize) {  
  156.                                         // 结束位置 等于 文件的大小  
  157.                                         endSize = size;  
  158.                                     }  
  159.                                 }  
  160.                                 // 为每一个线程创建一个随机的读取  
  161.                                 RandomAccessFile threadAccessFile = new RandomAccessFile(  
  162.                                         file, "rwd");  
  163.                                 new Thread(new DownLoadThread(i,  
  164.                                         threadAccessFile, startSize, endSize,  
  165.                                         path)).start();  
  166.                             }  
  167.   
  168.                         }  
  169.   
  170.                     }  
  171.   
  172.                 } catch (MalformedURLException e) {  
  173.                       
  174.                     e.printStackTrace();  
  175.                 } catch (IOException e) {  
  176.                       
  177.                     e.printStackTrace();  
  178.                 }  
  179.   
  180.             }  
  181.   
  182.         }).start();  
  183.     }  
  184.   
  185.     /** 
  186.      * 暂停操作 
  187.      *  
  188.      * @param v 
  189.      */  
  190.     public void downPause(View v) {  
  191.         Toast.makeText(this"暂停", Toast.LENGTH_LONG).show();  
  192.   
  193.         this.flag = false;  
  194.   
  195.     }  
  196.   
  197. }  


DownLoadThread.java

[java] view plaincopy
  1. package com.example.downloads.utils;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.RandomAccessFile;  
  9. import java.net.HttpURLConnection;  
  10. import java.net.MalformedURLException;  
  11. import java.net.URL;  
  12.   
  13. import com.example.downloads.DownActivity;  
  14.   
  15. import android.os.Environment;  
  16.   
  17.   
  18.   
  19. public class DownLoadThread implements Runnable {  
  20.   
  21.       
  22.     public RandomAccessFile accessFile; // 每一个线程 都拥有一个accessFile的文件对象 线程1 线程2 线程3  
  23.   
  24.     // 线程下载文件的起始位置  
  25.     public int startSize;  
  26.     public int endSize;  
  27.   
  28.     // 文件下载的path路径  
  29.     public String path;  
  30.   
  31.     public int threadId; // 线程的标识  
  32.   
  33.     public DownLoadThread(int threadId, RandomAccessFile accessFile,  
  34.             int startSize, int endSize, String path) {  
  35.   
  36.         this.threadId = threadId;  
  37.         this.accessFile = accessFile;  
  38.         this.startSize = startSize;  
  39.         this.endSize = endSize;  
  40.         this.path = path;  
  41.     }  
  42.   
  43.     @Override  
  44.     public void run() {  
  45.         // 运行run方法  
  46.         try {  
  47.   
  48.             // 创建文件到SD卡上去  
  49.   
  50.             // 首先推断是否拥有sdcard  
  51.             if (Environment.getExternalStorageState().equals(  
  52.                     Environment.MEDIA_MOUNTED)) {  
  53.                 // 获取sdCard文件文件夹对象  
  54.                 File sdFile = Environment.getExternalStorageDirectory();  
  55.                 File threadFile = new File(sdFile, threadId + ".txt");  
  56.   
  57.                 if (threadFile.exists()) {  
  58.   
  59.                     // 读取该文件的内容  
  60.                     // 创建文件的输入流对象  
  61.                     FileInputStream fis = new FileInputStream(threadFile);  
  62.                     // 採用工具类读取  
  63.                     byte data[] = StreamTools.isToData(fis);  
  64.                     // 转化成字符串  
  65.                     String threadLen = new String(data);  
  66.   
  67.                     if ((threadLen != null) && (!"".equals(threadLen))) {  
  68.                         startSize = Integer.valueOf(threadLen);  
  69.   
  70.                         // 解决 416bug的错误  
  71.                         if (startSize > endSize) {  
  72.                             startSize = endSize - 1;  
  73.                         }  
  74.                     }  
  75.   
  76.                 }  
  77.   
  78.                 // 创建文件  
  79.   
  80.                 // 创建URL对象  
  81.                 URL url = new URL(path);  
  82.                 // 创建HttpURLConnection对象  
  83.                 HttpURLConnection httpURLConnection = (HttpURLConnection) url  
  84.                         .openConnection();  
  85.                 // 设置请求的头  
  86.   
  87.                 httpURLConnection.setRequestMethod("GET");  
  88.                 // 设置请求是否超时时间  
  89.                 httpURLConnection.setConnectTimeout(5000);  
  90.                 // 设置  
  91.                 httpURLConnection  
  92.                         .setRequestProperty("User-Agent",  
  93.                                 " Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)");  
  94.   
  95.                 // 关键的设置  
  96.                 httpURLConnection.setRequestProperty("Range""bytes="  
  97.                         + startSize + "-" + endSize);  
  98.   
  99.                 // 输出当前线程  
  100.                 System.out.println("当前线程" + threadId + " 下载開始位置:" + startSize  
  101.                         + " 下载结束位置:" + endSize);  
  102.                 // 响应成功  
  103.   
  104.                 // 设置随机读取文件的 開始位置  
  105.                 accessFile.seek(startSize);  
  106.                 // 获取对应流对象  
  107.                 InputStream is = httpURLConnection.getInputStream();  
  108.                 // 创建输出流对象  
  109.   
  110.                 byte buffer[] = new byte[1024];  
  111.                 int len = 0;  
  112.                 int threadTotal = 0;// 每一个线程下载后保存记录 /  
  113.                 while ((len = is.read(buffer)) != -1) {  
  114.                     accessFile.write(buffer, 0, len);  
  115.                     threadTotal += len;// 记录你写入的长度 //xml文件  
  116.   
  117.                     //改变进度条:  
  118.                     setProgressBar(len);  
  119.                     // 通过文件记录文件下载的长度  
  120.                     FileOutputStream fos = new FileOutputStream(threadFile);  
  121.                     fos.write((threadTotal + "").getBytes());  
  122.                     fos.flush();  
  123.                     fos.close();  
  124.                     //发送handler消息  
  125.                     DownActivity.handler.sendEmptyMessage(DownActivity.TEXTVALUE);  
  126.                     if(!DownActivity.flag){  
  127.                         return;  
  128.                     }  
  129.   
  130.                 }  
  131.                 accessFile.close();  
  132.                 is.close();  
  133.                 System.out.println(threadId + "线程运行完成");  
  134.   
  135.                 // 线程操作  
  136.                 synchronized (DownActivity.class) {  
  137.                     DownActivity.threadCount++;  
  138.                     if (DownActivity.threadCount >= DownActivity.threadNum) {  
  139.                         for (int i = 1; i <= DownActivity.threadNum; i++) {  
  140.                             // 获取sdCard上的文件  
  141.                             File deleteFile = new File(sdFile, i + ".txt");  
  142.                             if (deleteFile.exists()) {  
  143.                                 // 文件删除  
  144.                                 deleteFile.delete();  
  145.                             }  
  146.                         }  
  147.                     }  
  148.                 }  
  149.             }  
  150.         } catch (MalformedURLException e) {  
  151.             // TODO Auto-generated catch block  
  152.             e.printStackTrace();  
  153.         } catch (IOException e) {  
  154.             // TODO Auto-generated catch block  
  155.             e.printStackTrace();  
  156.         }  
  157.   
  158.     }  
  159.   
  160.       
  161.       
  162.       
  163.     public synchronized void setProgressBar(int len){  
  164.         DownActivity.pb_count+=len;  
  165.         DownActivity.pb_thread.setProgress(DownActivity.pb_count);  
  166.     }  
  167.       
  168.       
  169.       
  170. }  


StreamTools.java

[java] view plaincopy
  1. package com.example.downloads.utils;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6.   
  7. public class StreamTools {  
  8.   
  9.       
  10.     public static byte[] isToData(InputStream is) throws IOException{  
  11.         // 字节输出流  
  12.         ByteArrayOutputStream bops = new ByteArrayOutputStream();  
  13.         // 读取数据的缓存区  
  14.         byte buffer[] = new byte[1024];  
  15.         // 读取长度的记录  
  16.         int len = 0;  
  17.         // 循环读取  
  18.         while ((len = is.read(buffer)) != -1) {  
  19.             bops.write(buffer, 0, len);  
  20.         }  
  21.         // 把读取的内容转换成byte数组  
  22.         byte data[] = bops.toByteArray();  
  23.           
  24.         bops.flush();  
  25.         bops.close();  
  26.         is.close();  
  27.         return data;  
  28.     }  
  29. }  


strings.xml

[html] view plaincopy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.   
  4.     <string name="app_name">downloads</string>  
  5.     <string name="action_settings">Settings</string>  
  6.     <string name="tv_down">文件下载的地址</string>  
  7.     <string name="tv_threadNum">线程数量</string>  
  8.     <string name="tv_num">0%</string>  
  9.     <string name="btn_text">下载</string>  
  10.     <string name="btn_pause">暂停</string>  
  11.     <string name="et_path">http://172.22.64.8:8080/doudou/youdao.exe</string>  
  12.     <string name="et_threadNum">3</string>  
  13.   
  14. </resources>  

布局文件:

[html] view plaincopy
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context=".DownActivity" >  
  10.   
  11.     <TextView  
  12.         android:id="@+id/textView1"  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:layout_alignParentLeft="true"  
  16.         android:layout_alignParentTop="true"  
  17.         android:text="@string/tv_down" />  
  18.   
  19.     <EditText  
  20.         android:id="@+id/et_path"  
  21.         android:layout_width="wrap_content"  
  22.         android:layout_height="wrap_content"  
  23.         android:layout_alignParentLeft="true"  
  24.         android:layout_alignParentRight="true"  
  25.         android:layout_below="@+id/textView1"  
  26.         android:ems="10"  
  27.         android:inputType="none"  
  28.         android:text="@string/et_path" >  
  29.   
  30.         <requestFocus />  
  31.     </EditText>  
  32.   
  33.     <TextView  
  34.         android:id="@+id/textView2"  
  35.         android:layout_width="wrap_content"  
  36.         android:layout_height="wrap_content"  
  37.         android:layout_alignParentLeft="true"  
  38.         android:layout_below="@+id/et_path"  
  39.         android:text="@string/tv_threadNum" />  
  40.   
  41.     <EditText  
  42.         android:id="@+id/et_threadNum"  
  43.         android:layout_width="wrap_content"  
  44.         android:layout_height="wrap_content"  
  45.         android:layout_alignLeft="@+id/textView2"  
  46.         android:layout_alignRight="@+id/et_path"  
  47.         android:layout_below="@+id/textView2"  
  48.         android:ems="10"  
  49.         android:inputType="number"  
  50.         android:text="@string/et_threadNum" />  
  51.   
  52.     <ProgressBar  
  53.         android:id="@+id/pb_down"  
  54.         style="?

    android:attr/progressBarStyleHorizontal"  

  55.         android:layout_width="wrap_content"  
  56.         android:layout_height="wrap_content"  
  57.         android:layout_alignLeft="@+id/et_threadNum"  
  58.         android:layout_alignRight="@+id/et_threadNum"  
  59.         android:layout_below="@+id/et_threadNum"  
  60.         android:layout_marginTop="14dp" />  
  61.   
  62.     <TextView  
  63.         android:id="@+id/tv_pb"  
  64.         android:layout_width="wrap_content"  
  65.         android:layout_height="wrap_content"  
  66.         android:layout_alignRight="@+id/textView1"  
  67.         android:layout_below="@+id/pb_down"  
  68.         android:layout_marginTop="24dp"  
  69.         android:text="@string/tv_num" />  
  70.   
  71.     <Button  
  72.         android:id="@+id/btn_down"  
  73.         android:layout_width="wrap_content"  
  74.         android:layout_height="wrap_content"  
  75.         android:layout_alignLeft="@+id/pb_down"  
  76.         android:layout_below="@+id/tv_pb"  
  77.         android:layout_marginTop="32dp"  
  78.         android:onClick="downLoad"  
  79.         android:text="@string/btn_text" />  
  80.   
  81.     <Button  
  82.         android:id="@+id/button1"  
  83.         android:layout_width="wrap_content"  
  84.         android:layout_height="wrap_content"  
  85.         android:layout_alignLeft="@+id/btn_down"  
  86.         android:layout_below="@+id/btn_down"  
  87.         android:layout_marginTop="16dp"  
  88.         android:onClick="downPause"  
  89.         android:text="@string/btn_pause" />  
  90.   
  91. </RelativeLayout>  

效果例如以下:


最后要注意的是别忘了在项目清单文件里增加权限:

[html] view plaincopy
  1. <!-- SDCard权限 -->  
  2.     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />  
  3.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />  
  4.     <!-- 訪问网络的权限 -->  
  5.     <uses-permission android:name="android.permission.INTERNET" />  

  1. http://blog.csdn.net/sgx425021234/article/details/9191963
原文地址:https://www.cnblogs.com/mfrbuaa/p/5203446.html