安卓系统下的多线程断点下载实现

安卓M3U8多线程下载器:断点续传与批量下载实战 本文详细解析安卓平台M3U8多线程下载器的核心功能与实战技巧,重点介绍其断点续传机制如何确保下载中断后无需重头开始,以及多线程加速和批量下载功能如何显著提升下载效率与文件管理能力,是移动端视频下载的实用指南。 阅读详情

最近研究多线程下载,写了个demo,整理下来,也许会对别人有帮助。
多线程下载的话一般开启两到三个线程吧。如果线程太多的话时间会浪费在线程的切换上,倒是浪费了大把的时间。线程多了也不是一件好事。
原理的话看我的另一篇博文,事实上是将代码移植到了安卓系统上。java实现的多线程下载demo

public class MainActivity extends Activity {
    protected static final int DOWNLOAD_ERROR = 1;
    private static final int THREAD_ERROR = 2;
    public static final int DWONLOAD_FINISH = 3;
    private EditText et_path;
    private EditText et_count;
    /**
     * 存放进度条的布局
     */
    private LinearLayout ll_container;

    /**
     * 进度条的集合
     */
    private List<ProgressBar> pbs;

    /**
     * android下的消息处理器,在主线程创建,才可以更新ui
     */
    private Handler handler = new Handler(){
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case DOWNLOAD_ERROR:
                Toast.makeText(getApplicationContext(), "下载失败", 0).show();
                break;
            case THREAD_ERROR:
                Toast.makeText(getApplicationContext(), "下载失败,请重试", 0).show();
                break;
            case DWONLOAD_FINISH:
                Toast.makeText(getApplicationContext(), "下载完成", 0).show();
                break;
            }
        };
    };

    /**
     * 线程的数量
     */
    private int threadCount = 3;

    /**
     * 每个下载区块的大小
     */
    private long blocksize;

    /**
     * 正在运行的线程的数量
     */
    private  int runningThreadCount;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_path = (EditText) findViewById(R.id.et_addr);
        et_count = (EditText) findViewById(R.id.et_num);
        ll_container = (LinearLayout) findViewById(R.id.ll_pb);
    }


    public void download(View view){
        //下载文件的路径
        final String path = et_path.getText().toString().trim();
        if(TextUtils.isEmpty(path)){
            Toast.makeText(this, "对不起下载路径不能为空", 0).show();
            return;
        }
        String count = et_count.getText().toString().trim();
        if(TextUtils.isEmpty(path)){
            Toast.makeText(this, "对不起,线程数量不能为空", 0).show();
            return;
        }
        threadCount = Integer.parseInt(count);
        //清空掉旧的进度条
        ll_container.removeAllViews();
        //在界面里面添加count个进度条
        pbs = new ArrayList<ProgressBar>();
        for(int j=0;j<threadCount;j++){
            ProgressBar pb = (ProgressBar) View.inflate(this, R.layout.pb, null);
            ll_container.addView(pb);
            pbs.add(pb);
        }
        Toast.makeText(this, "开始下载", 0).show();
        new Thread(){
            public void run() {
                try {
                    URL url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.setConnectTimeout(5000);
                    int code = conn.getResponseCode();
                    if (code == 200) {
                        long size = conn.getContentLength();// 得到服务端返回的文件的大小
                        System.out.println("服务器文件的大小:" + size);
                        blocksize = size / threadCount;
                        // 1.首先在本地创建一个大小跟服务器一模一样的空白文件。
                        File file = new File(Environment.getExternalStorageDirectory(),getFileName(path));
                        RandomAccessFile raf = new RandomAccessFile(file, "rw");
                        raf.setLength(size);
                        // 2.开启若干个子线程分别去下载对应的资源。
                        runningThreadCount = threadCount;
                        for (int i = 1; i <= threadCount; i++) {
                            long startIndex = (i - 1) * blocksize;
                            long endIndex = i * blocksize - 1;
                            if (i == threadCount) {
                                // 最后一个线程
                                endIndex = size - 1;
                            }
                            System.out.println("开启线程:" + i + "下载的位置:" + startIndex + "~"
                                    + endIndex);
                            int threadSize = (int) (endIndex - startIndex);
                            pbs.get(i-1).setMax(threadSize);
                            new DownloadThread(path, i, startIndex, endIndex).start();
                        }
                    }
                    conn.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                    Message msg = Message.obtain();
                    msg.what = DOWNLOAD_ERROR;
                    handler.sendMessage(msg);
                }

            };
        }.start();

    }
    private class DownloadThread extends Thread {

        private int threadId;
        private long startIndex;
        private long endIndex;
        private String path;

        public DownloadThread(String path, int threadId, long startIndex,
                long endIndex) {
            this.path = path;
            this.threadId = threadId;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        @Override
        public void run() {
            try {
                // 当前线程下载的总大小
                int total = 0;
                File positionFile = new File(Environment.getExternalStorageDirectory(),getFileName(path)+threadId + ".txt");
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url
                        .openConnection();
                conn.setRequestMethod("GET");
                // 接着从上一次的位置继续下载数据
                if (positionFile.exists() && positionFile.length() > 0) {// 判断是否有记录
                    FileInputStream fis = new FileInputStream(positionFile);
                    BufferedReader br = new BufferedReader(
                            new InputStreamReader(fis));
                    // 获取当前线程上次下载的总大小是多少
                    String lasttotalstr = br.readLine();
                    int lastTotal = Integer.valueOf(lasttotalstr);
                    System.out.println("上次线程" + threadId + "下载的总大小:"
                            + lastTotal);
                    startIndex += lastTotal;
                    total += lastTotal;// 加上上次下载的总大小。
                    fis.close();
                    //存数据库。
                    //_id path threadid total
                }

                conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
                        + endIndex);

                conn.setConnectTimeout(5000);
                int code = conn.getResponseCode();
                System.out.println("code=" + code);
                InputStream is = conn.getInputStream();
                File file = new File(Environment.getExternalStorageDirectory(),getFileName(path));
                RandomAccessFile raf = new RandomAccessFile(file, "rw");
                // 指定文件开始写的位置。
                raf.seek(startIndex);
                System.out.println("第" + threadId + "个线程:写文件的开始位置:"
                        + String.valueOf(startIndex));
                int len = 0;
                byte[] buffer = new byte[1024];
                while ((len = is.read(buffer)) != -1) {
                    RandomAccessFile rf = new RandomAccessFile(positionFile,
                            "rwd");
                    raf.write(buffer, 0, len);
                    total += len;
                    rf.write(String.valueOf(total).getBytes());
                    rf.close();
                    pbs.get(threadId-1).setProgress(total);
                }
                is.close();
                raf.close();

            } catch (Exception e) {
                e.printStackTrace();
                Message msg = Message.obtain();
                msg.what = THREAD_ERROR;
                handler.sendMessage(msg);
            } finally {
                // 只有所有的线程都下载完毕后 才可以删除记录文件。
                synchronized (MainActivity.class) {
                    System.out.println("线程" + threadId + "下载完毕了");
                    runningThreadCount--;
                    if (runningThreadCount < 1) {
                        System.out.println("所有的线程都工作完毕了。删除临时记录的文件");
                        for (int i = 1; i <= threadCount; i++) {
                            File f = new File(Environment.getExternalStorageDirectory(),getFileName(path)+ i + ".txt");
                            System.out.println(f.delete());
                        }
                        Message msg = Message.obtain();
                        msg.what = DWONLOAD_FINISH;
                        handler.sendMessage(msg);
                    }
                }

            }
        }
    }

    private String getFileName(String path){
        int start = path.lastIndexOf("/")+1;
        return path.substring(start);
    }

}

这里写图片描述
安卓系统下需要加上访问网络的权限和访问本地内存卡的权限。如下图:
这里写图片描述
源码已经上传到了CSDN: http://download.csdn.net/detail/rootusers/8508137

告别“静态组件”:Adobe XD的堆栈+状态,打造“活”的响应式UI 今天,我想分享一套能彻底告别这种“笨方法”的、Adobe XD中的进阶技巧,通过组合使用“堆栈”、“内边距”和“组件状态”,去构建一个能自动适应内容、真正“活”起来的智能响应式组件。 阅读详情

相关推荐

基于单片机电能质量检测仪设计

*单片机设计介绍,基于单片机电能质量检测仪设计。

2201_75940997的博客 1177

安卓系统下的多线程断点下载实现2利用开源框架XUtils

使用开源框架可以大大降低开发的难度,减少开发的周期,并且bug也少的多,软件运行起来更稳定。xUtils简介xUtils 包含了很多实用的android工具。 xUtils 支持大文件上传,更全面的http请求协议支持(10种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响… xUitls 最低兼容android 2.2 (api level 8)下载地址:https://gith

BIGBurning 1765

Adobe Acrobat DC

Adobe Acrobat DC为Adobe出品的PDF查看和编辑软件,下文简称Adobe DC,该软件功能强大,拥有查看PDF、编辑PDF、打印PSD、导出PDF、合并文件、组织页面、文本标注、注释、动作向导、等功能。

Android多任务并行下载断点续传

这个开源库叫 Aria,是我在搞断点续传时发现的,仔细了解后发现,真香!!! 它是一个简单易用,稳当高效的下载框架,不仅可以断点续传,还支持多任务自动调度,它更加灵活的事件监听器,让你能更容易的监听暂停、恢复、完成、失败、取消下载等状态。 开源库地址是:https://github.com/AriaLyy/Aria 目前已经有3.2k star,Aria有以下特点: 简单、方便 可以在Acti...

程序员大佬超的博客 3203

多线程+断点续传

首先是我们的布局<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_p

qq_40332973的博客 283

安卓多线程下载文件(一)

本文介绍了如何在安卓应用中实现多线程下载文件的功能,并支持断点续传。首先,通过比喻将文件下载比作搬运砖块,解释了多线程下载的原理。接着,设计了用于记录线程信息的数据表,包括线程编号、文件地址、下载起始位置、结束位置、已下载字节数和文件总长度等字段。然后,创建了一个继承自SQLiteOpenHelper的数据库帮助类DBHelper,用于管理线程信息表的创建和更新。最后,定义了一个ThreadInfo实体类,用于存储每个线程的下载信息。通过这些步骤,开发者可以实现一个高效且支持断点续传的文件下载功能。

csdn_too的博客 875

Android带通知栏操作多页面同步暂停支持多任务多线程断点下载demo

最近项目需要一个下载模块,要求多任务多线程断点下载还要通知栏提示,网上找了很多都没合适的,后面下了xutil做 成了这个demo希望可以给有同样需求的朋友一个参考,这个是我做项目前的测试demo所有有些细节可能没有完善,不过 大致功能还是可以实现的,有什么不足还希望大家指出,一起学习一起进步! 在xUtil基础上修改,支持多任务多线程断点下载,同时通知栏显示不卡顿,多个activity切

u012399891的博客 3706

Android多线程下载原理

多线程下载介绍 多线程背景知识 多线程下载任务可以更快完成文件的下载多线程下载文件之所以快,是因为其抢占的服务器资源多。如:假设服务器同时最多服务100个用户,在服务器中一条线程对应一个用户,100条线程在计算机中并非并发执行,而是由cpu划分时间片轮流执行,如果A应用使用了99条线程下载文件,那么相当于占用了99个用户的资源,假设一秒内cpu分配给每条线程的平均执行时间是10ms,A应用在

qq_22226691的博客 832

Android多线程断点续传下载文件类设计

对于Android平台,很多网友可能考虑开发一个软件商店,对于Android平台上如何实现断点续传操作呢? 这里Android123给大家一些思路和原理的介绍,同时在Android手机上要考虑的一些事情。   1. 流量控制,获取运营商的接入方式,比如说使用移动网络接入,尽可能的提示用户切换WiFi或提示,限制下载的流量以节省话费。   2. 屏幕锁控制,屏幕锁屏后导致应用会被挂起,当

frdde的专栏 853

asp.net core文档下载_Android多任务并行下载断点续传

多任务并行下载断点续传,要做起来其实还是很麻烦的,所以推荐一个开源库,这个开源库叫 Aria,刚好是我前一久搞断点续传时发现的,仔细了解后发现,真香!!!它简单易用,是个稳当高效的下载框架,不仅可以断点续传,还支持多任务自动调度,更加灵活的事件监听器,让你能更容易的监听暂停、恢复、完成、失败、取消下载等状态。开源库地址是:https://github.com/AriaLyy/Aria目前已经有3...

weixin_39731107的博客 265

我的Android进阶之旅------>Android基于HTTP协议的多线程断点下载器的实现

一、首先写这篇文章之前,要了解实现Android多线程断点下载器的几个知识点 1.多线程下载的原理,如下图所示 注意:由于Android移动设备和PC机的处理器还是不能相比,所以开辟的子线程建议不要多于5条。当然现在某些高端机子的处理器能力比较强了,就可以多开辟几条子线程。 2、为了实现断点下载,采用数据库方式记录下载的进度,这样当你将该应用退出后,下次点击下载的时候,程序会去查看该下...

移动编程 230

ua获取手机型号_拦都拦不住,速度太快了!安卓手机上最强大的不限速多线程下载神器来了,支持百度网盘下载...

随着 4G/5G 网络的普及,三大运营商推出的手机套餐流量越来越便宜,手机内存也越来越大,以及到处可用的 WiFi 热点。现如今,在手机上下载电影视频、超大文件甚至是BT资源,已逐渐成为人们的日常需求。在 Win 和 Mac 系统上有 IDM、Folx 这样的多线程下载工具,以及 Downie 视频下载利器。而在手机端,我们更需要一款具有下载加速、断点续传和视频下载功能的软件。今天小编就...

weixin_39622419的博客 1003

Android原生下载(上篇)基本逻辑+断点续传

零、前言 1.今天带来的是Android原生下载的上篇,主要核心是断点续传,多线程下载将会在下篇介绍 2.本例使用了Activity,Service,BroadcastReceiver三个组件 3.本例使用了两个线程:LinkURLThread做一些初始工作,DownLoadThread进行核心下载工作 4.本例使用SQLite进行暂停时的进度保存,使用...

张风捷特烈的博客 1819

推荐一个必备的开源项目 (附下载链接)

点击上方“阿拉奇学Java”,选择“置顶或者星标”优质文章第一时间送达!推荐阅读 |大白话讲解技术专业用语很多人都会遇到下载相关的需求,如果是只下载一个文件那还好,可需求有时候并不会那...

qq_36189144的博客 656

手机端满速下载方案:多线程下载管理器配置与速度优化实战

在移动互联网时代,文件下载是用户获取资源的基础操作。其核心原理是通过网络协议从服务器获取数据并存储到本地。传统的单线程下载方式往往无法充分利用网络带宽,导致速度受限。多线程下载技术通过将文件分割为多个部分并同时下载,有效突破了单线程瓶颈,显著提升了传输效率,具有极高的技术价值。这项技术广泛应用于软件更新、媒体内容获取、开发资源下载等场景。本文聚焦于手机端,深入探讨如何通过配置专业的下载管理器(如ADM等),调整线程数、连接数等关键参数,并结合网络环境优化,实现稳定、高效的满速下载体验,解决资源占用高、操作复

weixin_33812433的博客 367

番茄小说下载工具:3分钟搞定离线阅读全攻略 [特殊字符]

还在为网络不稳定无法追更小说而烦恼吗?Tomato小说下载工具帮你彻底解决这个问题!这款专为小说爱好者打造的便捷下载工具,能够一键抓取番茄小说平台内容并生成标准EPUB格式电子书,让你随时随地享受离线阅读的乐趣。 ## 🎯 你的阅读痛点,我来解决 想象一下这样的场景:地铁通勤时网络信号时断时续,好不容易找到心仪的小说却无法流畅阅读;或者深夜追更时担心章节突然下架……这些烦恼都将成为过去式!

gitblog_00538的博客 859

asp.net core文档下载_推荐一个必备的开源项目 (附下载链接)

点击上方“阿拉奇学Java”,选择“置顶或者星标”优质文章第一时间送达!推荐阅读 |大白话讲解技术专业用语很多人都会遇到下载相关的需求,如果是只下载一个文件那还好,可需求有时候并不会那么简单,领导一句话:下载要支持多任务并行下载,产品经理妹子再来一句:用户下载失败后,下次进来要能接着之前的继续下载,好像有个专业的名词,嗯,叫做断点续传。这个时候你的压力就来了:mmp,又要多任务并行,又...

weixin_39558804的博客 219

IDM下载器:全网最强下载神器,5倍极速体验,告别龟速时代(附安装教程)

到了这里,相信大家已经对 IDM 下载器有了全面的了解,不管是电脑端还是安卓端,IDM 都能满足新手的所有下载需求,总结一下它的核心优势,为什么值得所有新手入手:速度快:最高提速 5-8 倍,告别龟速下载,节省大量时间,尤其是下载大文件时,优势碾压其他下载工具;操作简单:自动捕获链接,无需手动复制粘贴,小白上手即会,下载、安装全流程简单,不用花费时间学习;功能全:断点续传、视频嗅探、计划任务、自动分类、批量下载等功能,覆盖所有下载场景,电脑端、安卓端都能用;

miaomiaowudi1的博客 417

安卓服务(Service)的两种开启方式以及服务的生命周期

安卓中服务的开启方式一:采用start的方式开启服务调用函数:startService(Intent)->onCreate()->onStart()/onStartCommand()->onDestroy() 特点:服务被开启后不会重复开启,只会调用onStart(),服务只会被停止一次。 二:采用bind的方式开发服务 调用函数:bindService(Intent…)->onCreate(

BIGBurning 4425
上一篇: Java之多线程断点下载的实现
下一篇: 安卓系统下的多线程断点下载实现2利用开源框架XUtils
BIGBurning
博客等级 码龄12年 625粉丝 59原创
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值