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

本文详细介绍了XUtils开源项目中的多线程下载功能,包括其实现原理及使用方法。通过实例展示了如何利用XUtils进行多线程断点续传下载,并提供了核心代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
            }
        });

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

一个Android基于快速开发的一个框架 xUtils 它是在aFinal基础上进行重构和扩展的框架 相比aFinal有很大的改善 同时 如果如果你的应用是基于网络的 那么只要处理得当 它会让你彻底的摆脱各种工具类和重复代码的困扰 xUtils 包含了很多实用的android工具 xUtils 源于Afinal框架 对Afinal进行了大量重构 使得xUtils支持大文件上传 更全面的http请求协议支持 拥有更加灵活的ORM 更多的事件注解支持且不受混淆影响 xUtils的四大组件: 一 ViewUtils 你受够了重复冗长的findViewById了嘛 你受够了各种监听事件的绑定了嘛 在这里 你只需要一句注解 如@ViewInject @OnClick 就能轻松摆脱小白似的代码 大大的上了一个档次 二 HttpUtils 支持的HTTP七种请求方式 非常便捷的满足你的接口请求的需要 同时还支持大文件上传下载 以及同步异步请求 三 BitmapUtils 你的程序因OOM强制关闭过嘛 你在为加在网络图片头疼嘛 有了组件 你将永久摆脱前面的问题 四 DbUtils 简单易用又出色的ORM框架 真的是谁用谁知道 直接轻松存储各种对象到sqlite数据库中 同时也能非常方便的进行各种条件查询 甚至分页查询 还有对表中数据的更新删除等操作 真正的实现 一行代码就可以进行增删改查 并且可通过注解自定义表名 列名 外键 唯一性约束 NOT NULL约束 CHECK约束等 支持事务 摘自github ">一个Android基于快速开发的一个框架 xUtils 它是在aFinal基础上进行重构和扩展的框架 相比aFinal有很大的改善 同时 如果如果你的应用是基于网络的 那么只要处理得当 它会让你彻底的摆脱各种工具类和重复代码的困扰 [更多]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值