android开发之多线程断点下载

由于xUtils开发框架的兴起,我们的程序猿就在请求网络获取数据或者下载服务器资源方面可以说是解脱了,但我们不能一直依靠这牛逼的开源框架还得知其然知其所以然.

那么,接下来我就和大家侃侃多线程断点下载!

多线程下载核心代码:

public class MulThreadDownUtil {
    //资源下载地址
    private static final String URL = "http://dlsw.baidu.com/sw-search-sp/soft/2a/25677/QQ_V4.0.2.1427684136.dmg";
    //线程数量
    private static final int THREAD_COUNT = 3;
    public static void main(String[] args) throws IOException {
        URL url = new URL(URL);
        //获取Http与服务器交互的对象
        HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
        //设置请求方式
        conn.setRequestMethod("GET");
        //设置请求超时
        conn.setConnectTimeout(5000);
        //200返回码 表示请求成功
        if((conn.getResponseCode()) == 200) {
            //获取服务器资源总大小
            int totalLength = conn.getContentLength();
            //在内存中创建一份与服务器资源总大小一致的文件
            RandomAccessFile raf = new RandomAccessFile("QQ.dmg","rw");
            raf.setLength(totalLength);
            raf.close();

            //开启子线程下载服务器资源
            //1.给每个子线程分配下载的区域大小
            int blockSize = totalLength / THREAD_COUNT;
            for(int threadID = 0;threadID < THREAD_COUNT;threadID++) {
                //开始下载位置
                int startIndex = blockSize * threadID;
                //结束下载位置
                int endIndex = (threadID + 1) * blockSize - 1;

                //PS: 特殊情况 如果是最后一个线程
                if(threadID == THREAD_COUNT - 1) {
                    endIndex = totalLength - 1;
                }
                //开启线程下载服务器资源
                new DownLoadThread(threadID,startIndex,endIndex,URL).start();
            }
        }
    }

    private static class DownLoadThread extends Thread{

        private int threadID,startIndex,endIndex;
        //线程当前下载的位置
        private int currentPosition;
        //上一次下载的大小
        private int lastDownSize;
        private String url;
        public DownLoadThread(int threadID,int startIndex,int endIndex,String URL){
            this.threadID = threadID;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.url = URL;
        }

        public void run() {
            /** * 断点下载 */
            currentPosition = startIndex;
            File infoFile = new File(threadID+".txt");
            if(infoFile.exists() && infoFile.length() > 0) {
                try {
                    FileInputStream fis = new FileInputStream(infoFile);
                    BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                    String str = br.readLine();
                    int currentPosition = Integer.parseInt(str);
                    fis.close();
                    //得到上次下载的大小
                    lastDownSize = currentPosition - startIndex;
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            try {
                //通过HttpURLConnection对象获取服务器资源
                URL url_ = new URL(url);
                HttpURLConnection conn = (HttpURLConnection) url_.openConnection();
                conn.setRequestMethod("GET");
                conn.setReadTimeout(5000);
                //设置请求参数,设置请求的范围 
                conn.setRequestProperty("Range","bytes="+currentPosition+"-"+endIndex);
                if((conn.getResponseCode()) == 206) {
                    InputStream is = conn.getInputStream();
                    RandomAccessFile raf = new RandomAccessFile("QQ.dmg","rwd");
                    //指定文件从哪个位置开始存放数据
                    raf.seek(currentPosition);
                    byte[] buffer = new byte[1024 * 1024];
                    int len = -1;
                    //当前线程下载的总大小
                    int total = 0;
                    while((len = is.read(buffer)) != -1) {
                        raf.write(buffer,0,len);
                        total += len;
                        //记录当前线程下载的位置
                        currentPosition = startIndex + lastDownSize + total;
                        //保证每一次数据都会真正的同步到底层硬盘设备里面
                        RandomAccessFile rafInfo = new RandomAccessFile(threadID+".txt","rwd");
                        rafInfo.write((""+currentPosition).getBytes());
                        rafInfo.close();
                    }
                    raf.close();
                    is.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

实现原理:

  1. 获取Http与服务器交互的对象(HttpURLConnection)
  2. 获取服务器资源总大小,并在内存中创建一份与服务器资源总大小一致的文件(RandomAccessFile raf = new RandomAccessFile(“QQ.dmg”,”rw”);)
  3. for循环开启子线程(一般情况下只开3个线程)下载服务器资源

    1. 给每个子线程分配下载的区域大小(int blockSize = totalLength / THREAD_COUNT;)
    2. 开始下载位置(int startIndex = blockSize * threadID;)和结束下载位置(int endIndex = (threadID + 1) * blockSize - 1;)
    3. 开启线程下载服务器资源(new DownLoadThread(threadID,startIndex,endIndex,URL).start();)
  4. 再一次通过HttpURLConnection对象获取服务器资源同时做断点下载操作

android开发之多线程断点下载_第1张图片

你可能感兴趣的:(java,多线程,android,下载)