android 多线程断点续传下载---强大的开源XUtils

来源:互联网 发布:js跨域请求有什么问题 编辑:程序博客网 时间:2024/05/20 06:08

XUtils

下面给大家介绍android的一个开源项目,它可以帮你干好多事情,废话不多说,步入正题:
这是xUtil的下载地址,在GitHub
目前xUtils主要的四大模块:

DbUtils模块:        android中的orm框架,一行代码就可以进行增删改查;        支持事务,默认关闭;        可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);        支持绑定外键,保存实体时外键关联实体自动保存或更新;        自动加载外键关联实体,支持延时加载;        支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。ViewUtils模块:        android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;        新的事件绑定方式,使用混淆工具混淆后仍可正常工作;        目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。HttpUtils模块:        支持同步,异步方式的请求;        支持大文件上传,上传大文件不会oom;        支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;        下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;        返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。BitmapUtils模块:        加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;        支持加载网络图片和本地图片;        内存管理使用lru算法,更好的管理bitmap内存;        可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等...

接下来,先给大家讲解一下多线程下载的原理:
如何实现多线程:
1 如何等分服务器资源 (RandomAccessFile)
2 如何在客户端创建一个大小和服务器一模一样的文件
3 如何开启多个线程
4 如何知道每个线程都下载完毕

path = “http://localhost:9019/01.exe“; 这个网址是我tomcat的服务器,你可以在tomcat的apache-tomcat-7.0.42\webapps\ROOT 文件夹下放一个exe文件,下载它,运行tomcat服务器,localhost是你电脑的IP地址。

下面我用java写一下多线程的原理:

import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;public class MutilDownload {    private static String path = "http://localhost:9019/01.exe";    private static int threadCount = 3;//线程的数量    private static int runningThread;//当前正在运行的线程    /**     * @param args     */    @SuppressWarnings("resource")    public static void main(String[] args) {        // 获取到服务器的资源        try {            URL url = new URL(path);            HttpURLConnection conn = (HttpURLConnection) url.openConnection();            conn.setRequestMethod("GET");            conn.setConnectTimeout(5000);            int code = conn.getResponseCode();            if (code == 200) {                // 1 获取服务器资源的大小                int length = conn.getContentLength();                System.out.println("length:" + length);                runningThread = threadCount;//当前正在运行的线程数                // 2 要知道如何从客户端创建一个大小和服务器一模一样的文件                RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rw");                raf.setLength(length);//设置和服务器大小一样的文件                // 3 如何等分服务器的资源 length                int threadBiockSize = length / threadCount;// 每个线程下载的大小                for (int i = 0; i < threadCount; i++) {                    int startIndex = i * threadBiockSize;// 每个线程下载开始的位置                    int endIndex = (i + 1) * threadBiockSize - 1;// 每个线程下载的结束位置                    // 最后一个线程                    if (i == threadCount - 1) {                        endIndex = length - 1;                    }                    System.out.println("线程id:"+i+"理论的下载位置--:"+startIndex+"-----"+endIndex);                    // 开启多个线程去下载                    new DownloadThread(path, startIndex, endIndex, i).start();                }            }        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * 开启多个线程下载     * @author Blake     *     */    private static class DownloadThread extends Thread {        private String path;        private int startIndex;        private int endIndex;        private int threadId;        @SuppressWarnings("unused")        public DownloadThread(String path, int startIndex, int endIndex,                int threadId) {            this.path = path;            this.startIndex = startIndex;            this.endIndex = endIndex;            this.threadId = threadId;        }        @SuppressWarnings("resource")        @Override        public void run() {            // 下载            try {                URL url = new URL(path);                HttpURLConnection conn = (HttpURLConnection) url.openConnection();                conn.setRequestMethod("GET");                conn.setConnectTimeout(5000);                // 断点续传 判断是否有下载的记录                File file = new File(threadId + ".txt");                if (file.exists() && file.length() > 0) {                    // 读取上次保存的位置                    FileInputStream fis = new FileInputStream(file);                    BufferedReader bfr = new BufferedReader(                            new InputStreamReader(fis));                    String lastPositin = bfr.readLine();// 上一次下载的位置                    // 按照上次的位置继续下载                    conn.setRequestProperty("Range", "bytes=" + lastPositin+ "-" + endIndex);                    //要改变一下statindex 的位置                    startIndex  = Integer.parseInt(lastPositin);                    System.out.println("线程id:"+threadId+"真实的下载位置--:"+startIndex+"-----"+endIndex);                    fis.close();                } else {                    // 因为开启多个线程去下载,要设置一个头信息,告诉服务器每个线程每个线程下载的位置                    conn.setRequestProperty("Range", "bytes=" + startIndex                            + "-" + endIndex);                }                int code = conn.getResponseCode();                if (code == 206) {// 返回服务器部分资源                    InputStream in = conn.getInputStream();                    // 把数据写到文件中                    RandomAccessFile raf = new RandomAccessFile(getFileName(path),"rw");                    raf.seek(startIndex);                    // 做断点续传 就是我把每个多线程下载的位置记录起来                    int len = -1;                    int total = 0;                    byte buffer[] = new byte[1024*1024];                    while ((len = in.read(buffer)) != -1) {                        raf.write(buffer, 0, len);                        // 记录当前线程下载的位置                        total += len;// 当前线程下载的大小                        int currentThreadPosition = startIndex + total;// 当前线程下载的位置                                                                        // 把这个位置记录下来                        RandomAccessFile rAccessFile = new RandomAccessFile(                                threadId + ".txt", "rwd");// 把数据同步到低层设备                        rAccessFile.write(String.valueOf(currentThreadPosition)                                .getBytes());                        rAccessFile.close();                    }                    raf.close();                    in.close();                    System.out.println("线程-----下载完毕" + threadId);                    //开一个锁                    synchronized (DownloadThread.class) {                        runningThread--;                        if (runningThread <=0) {                            //说明所有的线程都下载完毕 我把.txt文件删除                            for (int i = 0; i < threadCount; i++) {                                File deleteFile = new File(i+".txt");                                deleteFile.delete();                            }                        }                    }                }            } catch (Exception e) {                e.printStackTrace();            }            super.run();        }    }    /**     * 截取下载的路径     * @param path     * @return     */    public static String getFileName(String path){        int start=path.lastIndexOf("/")+1;        return path.substring(start);    }}

这是多线程下载的核心代码,看到这么多代码是不是很麻烦!!!!

接下我们用开源的项目来做就很简单了
1 首先把开源的com包导入项目中

HttpUtils http = new HttpUtils();        /**         * url 下载的路径         * target 下载文件保存的路径         * autoResume 是否支持断点续传         */        http.download("http://localhost:9019/01.exe", "/mnt/sdcard/haha.exe", true,new RequestCallBack<File>() {            @Override            public void onSuccess(ResponseInfo<File> responseInfo) {                Toast.makeText(getApplicationContext(), responseInfo.result.getPath(), 1).show();            }            @Override            public void onFailure(HttpException error, String msg) {            }            /**             * 加载进度 pb为进度条,实现进度条进度加载             * total 总得大小             * current 当前的大小             */            @Override            public void onLoading(long total, long current, boolean isUploading) {                pb.setMax((int) total);                pb.setProgress((int) current);            }        });

怎么样就这么几行代码,便实现了多线程断点续传下载和进度条加载进度。
还有更多的功能自己去探索吧!

1 2