Android学习(56) -- 断点续传多线程下载(Android)

Android学习(22) -- 数据存储之使用xml保存数据 在实际开发中,经常会用到xml来存储数据,比如:备份手机联系人,备份短信等等。我们以备份短信为例来讲解下xml的使用。 要想备份短信,那么我们就需要创建一个操作短信的JavaBean。如代码: public class Message { private String body; //短信内容 private String date; //时间 private String ad 阅读详情

手机版的断点续传多线程下载器

  • 把刚才的代码直接粘贴过来就能用,记得在访问文件时的路径要改成Android的目录,添加访问网络和外部存储的路径

用进度条显示下载进度

  • 拿到下载文件总长度时,设置进度条的最大值

    //设置进度条的最大值
    pb.setMax(length);
    
  • 进度条需要显示三条线程的整体下载进度,所以三条线程每下载一次,就要把新下载的长度加入进度条

    • 定义一个int全局变量,记录三条线程的总下载长度

      int progress;
      
    • 刷新进度条

      while((len = is.read(b)) != -1){
          raf.write(b, 0, len);
      
      
          //把当前线程本次下载的长度加到进度条里
          progress += len;
          pb.setProgress(progress);
      
  • 每次断点下载时,从新的开始位置开始下载,进度条也要从新的位置开始显示,在读取缓存文件获取新的下载开始位置时,也要处理进度条进度

    FileInputStream fis = new FileInputStream(file);
    BufferedReader br = new BufferedReader(new InputStreamReader(fis));
    String text = br.readLine();
    int newStartIndex = Integer.parseInt(text);
    
    //新开始位置减去原本的开始位置,得到已经下载的数据长度
    int alreadyDownload = newStartIndex - startIndex;
    //把已经下载的长度设置入进度条
    progress += alreadyDownload;
    

添加文本框显示百分比进度

    tv.setText(progress * 100 / pb.getMax() + "%");

核心代码

public class MainActivity extends Activity {

    static int ThreadCount = 3;
    static int finishedThread = 0;

    int currentProgress;
    String fileName = "QQPlayer.exe";
    //确定下载地址
    String path = "http://192.168.13.13:8080/" + fileName;
    private ProgressBar pb;
    TextView tv;

    Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            //把变量改成long,在long下运算
            tv.setText((long)pb.getProgress() * 100 / pb.getMax() + "%");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pb = (ProgressBar) findViewById(R.id.pb);
        tv = (TextView) findViewById(R.id.tv);
    }

    public void click(View v){

        Thread t = new Thread(){
            @Override
            public void run() {
                //发送get请求,请求这个地址的资源
                try {
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(5000);
                    conn.setReadTimeout(5000);

                    if(conn.getResponseCode() == 200){
                        //拿到所请求资源文件的长度
                        int length = conn.getContentLength();

                        //设置进度条的最大值就是原文件的总长度
                        pb.setMax(length);

                        File file = new File(Environment.getExternalStorageDirectory(), fileName);
                        //生成临时文件
                        RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                        //设置临时文件的大小
                        raf.setLength(length);
                        raf.close();
                        //计算出每个线程应该下载多少字节
                        int size = length / ThreadCount;

                        for (int i = 0; i < ThreadCount; i++) {
                            //计算线程下载的开始位置和结束位置
                            int startIndex = i * size;
                            int endIndex = (i + 1) * size - 1;
                            //如果是最后一个线程,那么结束位置写死
                            if(i == ThreadCount - 1){
                                endIndex = length - 1;
                            }
//                          System.out.println("线程" + i + "的下载区间是:" + startIndex + "---" + endIndex);
                            new DownLoadThread(startIndex, endIndex, i).start();
                        }
                    }
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        };
        t.start();
    }

    class DownLoadThread extends Thread{
        int startIndex;
        int endIndex;
        int threadId;

        public DownLoadThread(int startIndex, int endIndex, int threadId) {
            super();
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.threadId = threadId;
        }

        @Override
        public void run() {
            //再次发送http请求,下载原文件
            try {
                File progressFile = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
                //判断进度临时文件是否存在
                if(progressFile.exists()){
                    FileInputStream fis = new FileInputStream(progressFile);
                    BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                    //从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
                    int lastProgress = Integer.parseInt(br.readLine());
                    startIndex += lastProgress;

                    //把上次下载的进度显示至进度条
                    currentProgress += lastProgress;
                    pb.setProgress(currentProgress);

                    //发送消息,让主线程刷新文本进度
                    handler.sendEmptyMessage(1);
                    fis.close();
                }
                System.out.println("线程" + threadId + "的下载区间是:" + startIndex + "---" + endIndex);
                HttpURLConnection conn;
                URL url = new URL(path);
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);
                //设置本次http请求所请求的数据的区间
                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

                //请求部分数据,相应码是206
                if(conn.getResponseCode() == 206){
                    //流里此时只有1/3原文件的数据
                    InputStream is = conn.getInputStream();
                    byte[] b = new byte[1024];
                    int len = 0;
                    int total = 0;
                    //拿到临时文件的输出流
                    File file = new File(Environment.getExternalStorageDirectory(), fileName);
                    RandomAccessFile raf = new RandomAccessFile(file, "rwd");
                    //把文件的写入位置移动至startIndex
                    raf.seek(startIndex);
                    while((len = is.read(b)) != -1){
                        //每次读取流里数据之后,同步把数据写入临时文件
                        raf.write(b, 0, len);
                        total += len;
                        System.out.println("线程" + threadId + "下载了" + total);

                        //每次读取流里数据之后,把本次读取的数据的长度显示至进度条
                        currentProgress += len;
                        pb.setProgress(currentProgress);
                        //发送消息,让主线程刷新文本进度
                        handler.sendEmptyMessage(1);

                        //生成一个专门用来记录下载进度的临时文件
                        RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");
                        //每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中
                        progressRaf.write((total + "").getBytes());
                        progressRaf.close();
                    }
                    System.out.println("线程" + threadId + "下载完毕-------- ");
                    raf.close();

                    finishedThread++;
                    synchronized (path) {
                        if(finishedThread == ThreadCount){
                            for (int i = 0; i < ThreadCount; i++) {
                                File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
                                f.delete();
                            }
                            finishedThread = 0;
                        }
                    }

                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}
从‘炼丹’到‘讲理’:物理信息神经网络(PINN)的硬约束 vs 软约束,我该选哪个? 本文深入探讨了物理信息神经网络(PINN)中硬约束与软约束的选择策略,帮助研究者在深度学习中有效融入物理先验知识。通过对比两种约束方法的实现复杂度、数据效率和计算性能,提供了针对材料科学和流体动力学等领域的实用决策指南,并介绍了自适应约束和混合约束等前沿技术。 阅读详情

相关推荐

STM32F407 CubeMX UART DMA高效解析BNO085九轴数据

本文详细介绍了如何在STM32F407平台上使用CubeMX配置UART和DMA高效解析BNO085九轴传感器数据。通过DMA循环接收机制实现低CPU占用的实时数据采集,并分享数据解析技巧、错误处理及实战调试经验,为嵌入式开发者提供完整解决方案。

o4p5q6r7s的博客 235

Android 多线程断点下载project总结

Android断点续传下载详解

youngwm的专栏 1735

ComfyUI Impact Pack实战:如何用三大检测器打造高效人脸修复工作流(附2025最新模板)

本文详细解析了如何利用ComfyUI Impact Pack中的BBOX、Segm和SAM三大检测器构建高效人脸修复工作流。通过技术选型、参数优化和实战案例,帮助用户掌握从精准定位到细节修复的全流程技巧,特别适用于商业摄影和影视制作场景。文章还提供了2025年最新模板和性能优化方案,显著提升人脸精修效率。

weixin_29040367的博客 245

超经典,百度最爱考的安卓Android百题

针对于上面的问题,我总结出了互联网公司Android程序员面试涉及到的绝大部分面试题及答案,并整理做成了文档,以及系统的进阶学习视频资料。(包括Java在Android开发中应用、APP框架知识体系、高级UI、全方位性能调优,NDK开发,音视频技术,人工智能技术,跨平台技术等技术资料),希望能帮助到你面试前的复习,且找到一个好的工作,也节省大家在网上搜索资料的时间来学习。《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!上搜索资料的时间来学习。**

2301_77595001的博客 800

【七】Hadoop3.3.4基于ubuntu24的分布式集群安装

本次安装实验基于苹果m2芯片的mac系统,使用vmware fusion搭建三台ubuntu24分布式虚拟机,确保在三台机器上安装了Java jdk8,并配置了免密码登录,网络互通,防火墙关闭,授时服务器已经同步。访问apche官网源,下载3.3.4版本,我们用二进制通用版即可,因为hadoop运行在java环境,跨平台性使得无需编译arm架构版本。至此,Hadoop的安装完成,包括hdfs文件存储系统,mapreduce计算框架,yarn资源管理系统均能正常、稳定使用。

qq_31412425的博客 2161

代付系统/代付系统源码/支付宝代付系统/API代付系统

简介: 其他站买的,没有做测试,源码是JAVA的,附带了安装文档,需要的拿无售后 源码下载地址https://www.skpan.cn/2QnIARSZDxG 代付系统/代付系统源码/支付宝代付系统/API代付系统 系统流程: 后台开通代理——开通商户——商户做代付(后台手工提交和 api 提交两种方式) 1、纯代付系统 2、支持个人支付宝全自动 3、支持单笔/批量/API接口方式代付 4、支持白名单、谷歌验证 5、收付款模式采用自动回调/自动转账 一、运营平台 商户管.

刀客源码网 5579

软件:分享六款实用的软件,每一款值得收藏_前端知识电子书用什么软件看(1)

今天给大家分享六款实用的软件,每一款都堪称经典,一起来看看吧!

2401_84591870的博客 326

DeepSeek-V3本地Docker容器化部署

通过以上步骤,你可以在本地上成功通过容器化部署DeepSeek-V3。安装完成后,启动Docker Desktop。如果需要后台运行,可以加上。

u013302168的博客 2123

软件:分享六款实用的软件,每一款值得收藏_前端知识电子书用什么软件看

今天给大家分享六款实用的软件,每一款都堪称经典,一起来看看吧!

2401_84591930的博客 948

硬件学习手册【总目录】

欢迎大家来到《硬件学习手册》,专栏主要包括 《硬件经验手册》《电子元器件器件手册》《PCB手册》《CPU手册》《元器件选型手册》五个分册。在开始专栏的更新前,博主先列出专栏的大纲,以供大家参考。大家直接点击大纲中的蓝色标题即可轻松传送。

fydar的博客 5855

【Claude】媒体文件处理错误:PDF 与 Image 过大的检测与预处理方法 bug报错已解决

图片压缩是必须的:原始图片的 base64 会占用大量 TokenPDF 提取文本优于传图片:文本版 PDF 比扫描版更省 Token分块处理大文件:不要一次性处理整个大文件控制分辨率:800x800 通常足够 Claude 分析。

博客 6360

Android学习(21) -- Android版本号和API Level对应关系

Platform Version API Level VERSION_CODE Android 6.0 23 API Level Marshmallow Android 5.1 22 Lollipop Android 5.0 21 Lollipop

idiandi的博客 1万+

执行任务赚积分

接下来N行,每行两个空格分隔的整数(SLA和V),SLA表示任务的最晚处理时间,V表 示任务对应的积分。每个任务都有最晚处理时间限制和积分值,在最晚处理时间点之前处理完成任务才可获得对应的积分奖励。现有N个任务需要处理,同一时间只能处理一个任务,处理每个任务所需要的时间固定为1。可用于处理任务的时间有限,请问在有限的时间内,可获得的最多积分。第2个时间单位内,处理任务4,获得5个积分。输入描述:第一行为一个数N,表示有N个任务,1

面试高手的博客 4695

Android学习(28) -- 动态创建TextView并展示数据

我们在编程的时候,除了可以利用布局中的TextView来显示数据,同样我们也可以利用对象来动态创建TextView,并展示数据。 1、创建TextView对象 2、添加数据和属性值 3、把TextView设置为布局的子节点 4、如果需要滚动需要使用ScrollView LinearLayout ll = (LinearLayout) findViewById(R.id.

idiandi的博客 1万+

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

Android学习(45) -- 自定义控件(9) 下拉刷新 (添加footer)

样式效果 1、创建底部的布局 layout_footer.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"

idiandi的博客 2903

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Android学习(50) -- 使用post方式提交数据

要点 post提交数据是用流写给服务器的 协议头中多了两个属性 Content-Type: application/x-www-form-urlencoded,描述提交的数据的mimetype Content-Length: 30,描述提交的数据的长度 //给请求头添加post多出来的两个属性 String data = "name=" + URLEncoder.enco

idiandi的博客 2227

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Android学习(49) -- 使用get方式提交数据

get方式提交的数据是直接拼接在url的末尾 final String path = "http://192.168.1.103/Web/servlet/CheckLogin?name=" + name + "&pass=" + pass; 发送get请求,代码和之前一样 URL url = new URL(path); HttpURLConnection conn = (HttpURL

idiandi的博客 2005

Android学习(19) -- 数据存储之File (简单登录保存用户名和密码)

简介          使用内部存储方式进行保存用户名和密码          内部存储空间 存在/data/data//files下面,可以通过getFilesDir()获取到该路径          如果想在内部空间写入数据,只能写到自己的文件夹中,所以不需要在Manifest文件中添加权限 代码       登录并保存数据 public void login(View

idiandi的博客 1869

Intent实现Activity的跳转

Intent实现Activity的跳转 Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描述,Android则根据此Intent的描述,负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。 Intent不仅可用于应用程序之间,也可用于应用程序内部的Activity/Service/Br

idiandi的博客 1507

Android学习(42) -- 自定义控件(6)下拉选择实现( 动态ListView + popupWindow)

要实现的效果图 下拉列表使用的是  动态ListView + popupWindow实现   1、设置布局 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" andro

idiandi的博客 1468

Android学习(47) -- Html源文件查看器

Android学习(46) --  Html源文件查看器

idiandi的博客 1304

Android学习(36) -- 自定义控件(1)实现组合按钮的菜单和隐藏

自定义控件: 1.组合控件:将系统原生控件组合起来,加上动画效果,形成一种特殊的UI效果 2.纯粹自定义控件:继承自系统的View,自己去实现view效果 使用组合实现菜单 布局代码: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="

idiandi的博客 1275

Activity跳转时的数据传递

Intent是Activity与Activity之间,Activity与Service之间传递参数的介质,使用Intent和Bundle在组件之间传递数据,而这两种通常实现的是Java基本对象类型和String的传递。在实际项目中,页面之间传值,除了以上几种,经常还有传递Object对象、List类型、List类型和全局变量等等的需求。由于Activity跳转有两种方式,为此进行数据传递一共有两种方

idiandi的博客 1167

Android学习(48) -- 获取xml文件并解析.

1、根据xml的格式创建JavaBean public class News { private String title; private String detail; private String comment; private String imageUrl; @Override public String toString() { return "News [ti

idiandi的博客 1161

Android学习(38) -- 自定义控件(3)点击Menu键显示隐藏菜单

如果想实现点击Menu键显示隐藏菜单,那么就需要重写onKeyDown方法。想解决多次点击事件,动画无法完全执行,就需要AnimUtil类中定义一个静态变量,用于记录当前执行的动画数量。需要使用RotateAnimation中的setAnimationListener来实现对该静态变量的操作,当启动动画的时候进行对该变量进行自加操作,当结束动画的时候对该变量进行自减操作。        

idiandi的博客 1115
上一篇: Android学习(55) -- 带断点续传的多线程下载(Java)
下一篇: Android学习(57) -- xUtils简介使用
idiandi
博客等级 码龄11年 24粉丝 101原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值