zoukankan      html  css  js  c++  java
  • android多线程断点下载-带进度条和百分比进度显示

    欢迎访问个人博客:www.yyxxk.com

    android多线程断点下载,带进度条和百分比显示,断点下载的临时数据保存到SD卡的文本文档中,建议可以保存到本地数据库中,这样可以提高存取效率,从而提高系统性能。

    效果:

    打开软件:

    下载中:

    下载完毕:

    附代码如下:

      1 package com.yy.multiDownloadOfBreakPoint;
      2 
      3 import java.io.File;
      4 import java.io.FileInputStream;
      5 import java.io.InputStream;
      6 import java.io.RandomAccessFile;
      7 import java.net.HttpURLConnection;
      8 import java.net.URL;
      9 
     10 import android.app.Activity;
     11 import android.os.Bundle;
     12 import android.os.Handler;
     13 import android.os.Message;
     14 import android.text.TextUtils;
     15 import android.view.View;
     16 import android.widget.EditText;
     17 import android.widget.ProgressBar;
     18 import android.widget.TextView;
     19 import android.widget.Toast;
     20 /**
     21  * 多线程断点下载实例
     22  * @author YUANYUAN
     23  *
     24  */
     25 public class MainActivity extends Activity {
     26     //下载所使用的线程数
     27     protected static final int threadCount = 3;
     28     //下载完毕的标记
     29     public static final int downloadOver = 1;
     30     //更新下载进度标记
     31     public static final int UPDATE_PROGRESS = 0;
     32     //下载资源的路径输入框
     33     private EditText et_path;
     34     //下载的进度条
     35     private ProgressBar pb;
     36     //进度显示
     37     private TextView tv_pb;
     38     //当前累计下载的数据
     39     int curDownCount=0;
     40     //当前活动的下载线程数
     41     protected static int activeThread;
     42     //加入消息处理机制
     43     private Handler handler=new Handler(){
     44         @Override
     45         public void handleMessage(Message msg) {
     46             switch (msg.what) {
     47             case downloadOver:
     48                 Toast.makeText(MainActivity.this, "文件已下载完毕!", Toast.LENGTH_LONG).show();
     49                 tv_pb.setText("下载完成");
     50                 break;
     51             case UPDATE_PROGRESS:
     52                 //更新进度显示
     53                 tv_pb.setText("当前进度:"+(pb.getProgress()*100/pb.getMax())+"%");
     54                 break;
     55             default:
     56                 break;
     57             }
     58         }
     59     };
     60 
     61     @Override
     62     protected void onCreate(Bundle savedInstanceState) {
     63         super.onCreate(savedInstanceState);
     64         setContentView(R.layout.activity_main);
     65         et_path=(EditText) findViewById(R.id.et_path);
     66         et_path.setText("http://192.168.2.114:8080/sqlite.exe");
     67         pb=(ProgressBar) findViewById(R.id.pb);
     68         tv_pb=(TextView) findViewById(R.id.tv_pb);
     69     }
     70     
     71     /**
     72      * 开始下载
     73      * @param view
     74      */
     75     public void down(View view){
     76         //获取下载资源的路径
     77         final String path=et_path.getText().toString().trim();
     78         //判断资源路径是否为空
     79         if (TextUtils.isEmpty(path)) {
     80             Toast.makeText(this, "请输入下载资源的路径", Toast.LENGTH_LONG).show();
     81             return;
     82         }
     83         //开启一个线程进行下载
     84         new Thread(){
     85             public void run() {
     86                 try {
     87                     //构造URL地址
     88                     URL url=new URL(path);
     89                     //打开连接
     90                     HttpURLConnection conn=(HttpURLConnection) url.openConnection();
     91                     //设置请求超时的时间
     92                     conn.setConnectTimeout(5000);
     93                     //设置请求方式
     94                     conn.setRequestMethod("GET");
     95                     //获取相应码
     96                     int code=conn.getResponseCode();
     97                     if (code==200) {//请求成功
     98                         //获取请求数据的长度
     99                         int length=conn.getContentLength();
    100                         //设置进度条的最大值
    101                         pb.setMax(length);
    102                         //在客户端创建一个跟服务器文件大小相同的临时文件
    103                         RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd");
    104                         //指定临时文件的长度
    105                         raf.setLength(length);
    106                         raf.close();
    107                         //假设3个线程去下载资源
    108                         //平均每一个线程要下载的文件的大小
    109                         int blockSize=length/threadCount;
    110                         for (int threadId = 1; threadId <= threadCount; threadId++) {
    111                             //当前线程下载数据的开始位置
    112                             int startIndex=blockSize*(threadId-1);
    113                             //当前线程下载数据的结束位置
    114                             int endIndex=blockSize*threadId-1;
    115                             //确定最后一个线程要下载数据的最大位置
    116                             if (threadId==threadCount) {
    117                                 endIndex=length;
    118                             }
    119                             //显示下载数据的区间
    120                             System.out.println("线程【"+threadId+"】开始下载:"+startIndex+"---->"+endIndex);
    121                             //开启下载的子线程
    122                             new DownloadThread(path, threadId, startIndex, endIndex).start();
    123                             //当前下载活动的线程数加1
    124                             activeThread++;
    125                             System.out.println("当前活动的线程数:"+activeThread);
    126                         }
    127                         
    128                     }else{//请求失败
    129                         System.out.println("服务器异常,下载失败!");
    130                     }
    131                 } catch (Exception e) {
    132                     e.printStackTrace();
    133                     System.out.println("服务器异常,下载失败!");
    134                 }
    135             };
    136         }.start();
    137         
    138     }
    139     /**
    140      * 下载文件的子线程 每一个文件都下载对应的数据
    141      * @author YUANYUAN
    142      *
    143      */
    144     public class DownloadThread extends Thread{
    145         private String path;
    146         private int threadId;
    147         private int startIndex;
    148         private int endIndex;
    149         
    150         /**
    151          * 构造方法
    152          * @param path 下载文件的路径
    153          * @param threadId 下载文件的线程
    154          * @param startIndex 下载文件开始的位置
    155          * @param endIndex 下载文件结束的位置
    156          */
    157         public DownloadThread(String path, int threadId, int startIndex,
    158                 int endIndex) {
    159             this.path = path;
    160             this.threadId = threadId;
    161             this.startIndex = startIndex;
    162             this.endIndex = endIndex;
    163         }
    164 
    165 
    166 
    167         @Override
    168         public void run() {
    169             //构造URL地址
    170             try {
    171                 
    172                 File tempFile=new File("sdcard/"+threadId+".txt");
    173                 //检查记录是否存在,如果存在读取数据,设置真实下载开始的位置
    174                 if (tempFile.exists()) {
    175                     FileInputStream fis=new FileInputStream(tempFile);
    176                     byte[] temp=new byte[1024];
    177                     int length=fis.read(temp);
    178                     //读取到已经下载的位置
    179                     int downloadNewIndex=Integer.parseInt(new String(temp, 0, length));
    180                     //计算出已经下载的数据长度
    181                     int areadyDown=downloadNewIndex-startIndex;
    182                     //累加已经下载的数据量
    183                     curDownCount+=areadyDown;
    184                     //设置进度条已经下载的数据量
    185                     pb.setProgress(curDownCount);
    186                     //设置重新开始下载的开始位置
    187                     startIndex=downloadNewIndex;
    188                     fis.close();
    189                     //显示真实下载数据的区间
    190                     System.out.println("线程【"+threadId+"】真实开始下载数据区间:"+startIndex+"---->"+endIndex);
    191                 }
    192                 
    193                 URL url = new URL(path);
    194                 HttpURLConnection conn=(HttpURLConnection) url.openConnection();
    195                 conn.setConnectTimeout(5000);
    196                 conn.setRequestMethod("GET");
    197                 //设置请求属性,请求部分资源
    198                 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
    199                 int code=conn.getResponseCode();
    200                 if (code==206) {//下载部分资源,正常返回的状态码为206
    201                     InputStream is=conn.getInputStream();//已经设置了请求的位置,所以返回的是对应的部分资源
    202                     //构建随机访问文件
    203                     RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd");
    204                     //设置 每一个线程随机写文件开始的位置
    205                     raf.seek(startIndex);
    206                     //开始写文件
    207                     int len=0;
    208                     byte[] buffer=new byte[1024];
    209                     //该线程已经下载数据的长度
    210                     int total=0;
    211                     
    212                     while((len=is.read(buffer))!=-1){//读取输入流
    213                         //记录当前线程已下载数据的长度
    214                         RandomAccessFile file=new RandomAccessFile("sdcard/"+threadId+".txt","rwd");
    215                         raf.write(buffer,0,len);//写文件
    216                         total+=len;//更新该线程已下载数据的总长度
    217                         System.out.println("线程【"+threadId+"】已下载数据:"+(total+startIndex));
    218                         //将已下载数据的位置记录写入到文件
    219                         file.write((startIndex+total+"").getBytes());
    220                         //累加已经下载的数据量
    221                         curDownCount+=len;
    222                         //更新进度条【进度条的更新可以在非UI线程直接更新,具体见底层源代码】
    223                         pb.setProgress(curDownCount);
    224                         
    225                         //更新下载进度
    226                         Message msg=Message.obtain();
    227                         msg.what=UPDATE_PROGRESS;
    228                         handler.sendMessage(msg);
    229                         
    230                         file.close();
    231                     }
    232                     is.close();
    233                     raf.close();
    234                     //提示下载完毕
    235                     System.out.println("线程【"+threadId+"】下载完毕");
    236                 }
    237             } catch (Exception e) {
    238                 e.printStackTrace();
    239                 System.out.println("线程【"+threadId+"】下载出现异常!!");
    240             }finally{
    241                 //活动的线程数减少
    242                 activeThread--;
    243                 if (activeThread==0) {
    244                     for (int i = 1; i <= threadCount; i++) {
    245                         File tempFile=new File("sdcard/"+i+".txt");
    246                         tempFile.delete();
    247                     }
    248                     System.out.println("下载完毕,已清除全部临时文件");
    249                     //界面消息提示下载完毕
    250                     Message msg=new Message();
    251                     msg.what=downloadOver;
    252                     handler.sendMessage(msg);
    253                 }
    254             }
    255             
    256         }
    257     }
    258 }
  • 相关阅读:
    SpringMVC,3种不同的URL路由配置方法(这根本不是一个小问题)
    PHP在Windows下安装配置第一步
    跟我一起学extjs5(18--模块的新增、改动、删除操作)
    html image -- data:image/png;base64
    oc66--代理模式应用2
    oc65--协议应用1,接口.做数据类型限定
    oc64--协议2@protocol
    oc63--协议@protocol1
    oc62--block1
    oc61--block
  • 原文地址:https://www.cnblogs.com/javayuan/p/4947407.html
Copyright © 2011-2022 走看看