断点续传android版本

多线程下载之断点续传android版本
第一个页面布局

<RelativeLayout 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: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/en_path"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="http://192.168.80.212:8080/feiqiu.exe"
        android:hint="请输入下载路径" />

    <EditText
        android:id="@+id/en_threadCount"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="55dp"
        android:hint="请输入下载线程数量" >
    </EditText>

    <Button
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_margin="90dp"
        android:onClick="click"
        android:text="下载" />
<!-- 写一个线性布局,动态的添加布局 -->
    <LinearLayout
        android:id="@+id/ll_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="200dp"
        android:orientation="vertical" >
    </LinearLayout>

</RelativeLayout>

第二个页面布局

<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/progressBar1"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

</ProgressBar>

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;


public class MainActivity extends Activity {

    private EditText en_path;
    private EditText en_threadCount;
    private List<ProgressBar> pbs;
    private int runningThread ;
    private int threadCount;
    private LinearLayout ll_layout;
    private String downThreadCount;
    private String downloadPath;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取我们关心的控件
        en_path = (EditText) findViewById(R.id.en_path);
        en_threadCount = (EditText) findViewById(R.id.en_threadCount);
        ll_layout = (LinearLayout) findViewById(R.id.ll_layout);
        pbs = new ArrayList<ProgressBar>();
    }


  public void click(View v) {
      downloadPath = en_path.getText().toString().trim();
      downThreadCount = en_threadCount.getText().toString().trim();
      //将从控件获取到的下载数量转换为int型
      threadCount = Integer.parseInt(downThreadCount);    
      //清除集合和进度条
     ll_layout.removeAllViews();  //清除集合中的进度条
     pbs.clear();
     //有几个线程就添加几个进度条
     for (int i = 0; i < threadCount; i++) {
        ProgressBar pb = (ProgressBar) View.inflate(getApplication(), R.layout.item, null);
        pbs.add(pb);             //将进度条添加到集合
        ll_layout.addView(pb);   //将进度条添加到布局
    }
     //开启子线程
     new Thread() {
        public void run() {
            try {
                URL url = new URL(downloadPath);
                HttpURLConnection con = (HttpURLConnection) url
                        .openConnection();
                con.setRequestMethod("GET");
                con.setConnectTimeout(5000);
                int code = con.getResponseCode();
                if (code == 200) {
                    //从服务器获取文件的长度
                    int length = con.getContentLength();  
                    //将线程数赋值
                    runningThread = threadCount;
                    //将文件写到内存
                    RandomAccessFile rafAccessFile  = new RandomAccessFile(getFileName(downloadPath), "rw");
                    rafAccessFile.setLength(length);  //设置该文件的大小

                    int blockSize = length / threadCount;    //得到每个线程下载的总大小

                    for (int i = 0; i < threadCount; i++) {
                        int startIndex = i * blockSize;      //计算每个线程出开始的位置
                        int endIndex = (i + 1) * blockSize;  //计算每个线程的结束位置
                    if(i == threadCount - 1){                //计算最后一个线程的位置
                        endIndex = length - 1;
                    }
                    new DownLoadThread(i,startIndex,endIndex).start();  //开启线程下载
                    }

                }
            } catch (Exception e) {

                e.printStackTrace();
            }
        }
    }.start();

}
  //下载文件
  class DownLoadThread extends Thread{
      private int threadid;   //线程id
      private int startIndex; //线程的开始位置
      private int endIndex;   //线程的结束位置
      private int pbMax;      //进度条的最大值
      private int pbLastPosition;  //进度条的当前位置
      public DownLoadThread(int threadid,int startIndex,int endIndex){
          this.threadid = threadid;
          this.startIndex = startIndex;
          this.endIndex = endIndex;
      }

      @Override
    public void run() {
        try {
            pbMax = endIndex - startIndex;     //计算出进度条的最大值
            URL url = new URL((downloadPath));
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("GET");
            con.setConnectTimeout(5000);
            //如果线程下载过程中中断过,则走下面的 if语句,没有则跳过该语句继续执行
            File file = new File(getFileName(downloadPath) + threadid + ".txt");  //存储每个线程的txt文件
            if(file.exists() && file.length() > 0){
                //用高效的字符流关联该文件
                BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
                String lastPosition = br.readLine();
                pbLastPosition = Integer.parseInt(lastPosition);
                startIndex = Integer.parseInt(lastPosition);   //将读取出来的数据作为当前线程的开始位置
                 br.close();
            }
            //设置Range头,指定下载的开始位置和结束位置
            con.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

            int code = con.getResponseCode();
            if (code == 206) {       //请求资源部分求成功
                InputStream in = con.getInputStream();
                RandomAccessFile raf = new RandomAccessFile(getFileName(downloadPath), "rw");
                raf.seek(startIndex); //设置文件的开始位置

                int len;
                int total = 0;
                byte[] arr = new byte[1024*1024];
                while((len = in.read(arr)) != -1){   
                    total += len;  //获取到正在下载的长度并累加
                    int currentThreadPosition = startIndex + total;   //将当前下载的长度和开始位置相加得到线程当前的位置

                    //创建一个当前线程的txt文件,用于存储中断时的位置
                    RandomAccessFile accessFile = new RandomAccessFile(getFileName(downloadPath) + threadid + ".txt", "rwd");
                    //将此位置写入到文件中
                    accessFile.write(String.valueOf(currentThreadPosition).getBytes());
                    accessFile.close();
                    //下载数据(将数据写到文件中,此文件为.exe(以飞秋为例)形式)
                    raf.write(arr, 0, len);
                    //设置进度条的大小
                    pbs.get(threadid).setMax(pbMax);   //进度条的最大值
                    //设置进度条的当前位置
                    pbs.get(threadid).setProgress(pbLastPosition + total - startIndex);
                }
                //关流
                in.close();
                raf.close();
                //为什么不用threadCount--,而是给它赋值为runningThread在操作呢?
                //个人理解:如果直接操作threadCount,那么当threadCount出现错误时全局都会受到影响
                //但是如果操作runningThread出现错误时,并不会对全局造成影响,并且代码容易维护
                synchronized ((DownLoadThread.class) ) {//同步:是为了在当前线程能够完全执行,其他线程不中断当前线程
                    runningThread --;
                    if(runningThread == 0){ //如果正在运行的线程等于0,则将生成的临时文件删除
                        for (int i = 0; i < threadCount; i++) {
                            File txtfile = new File(getFileName(downloadPath) + i + ".txt");
                            txtfile.delete();

                        }
                    }
                }

            }
        } catch (Exception e) {

            e.printStackTrace();
        }

    }
  }

  public static String getFileName(String path){
      int start = path.lastIndexOf("/") + 1;
      String sdCard = Environment.getExternalStorageDirectory().getPath();
      return sdCard + "/" + path.substring(start);
  }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值