Android -- 多线程下载

简介:

因为Android应用程序是java写的,基本上很多java写的程序都可以直接照搬到Android上面,移植性非常Good。这里讲一下多线程下载,就是每个线程都下载自己的那部分,那么就需要平均分配分割线程下载多少,一张图来说明一下。

image

第一个要点:http头里面有一个”Range”,就是在这里设置从哪里开始下载。

第二个要点:RandomAccessFile,java给出的这个API。

分别开启多个线程,每个线程规定得有下载的大小,然后分别下载,下载下来的inputstream再组合在一起,怎么组合呢,就会用到RandomAccessFile。

downLoad函数                                                                          

复制代码
public void downLoad() throws Exception {
        currentProcess = 0;
        new Thread() {

            @Override
            public void run() {
                URL url;
                try {
                    url = new URL(path);
                    HttpURLConnection conn = (HttpURLConnection) url
                            .openConnection();
                    conn.setConnectTimeout(5000);
                    conn.setRequestMethod("GET");
                    int code = conn.getResponseCode();
                    System.out
                            .println("int code = conn.getResponseCode();---------->"
                                    + code);
                    if (code == 200) {
                        // 服务器返回的数据的长度,实际上就是文件的长度
                        int length = conn.getContentLength();
                        System.out.println("文件总长度" + length);

                        // 在客户端本地创建出来一个大小跟服务器端文件大小一样的临时文件
                        RandomAccessFile raf;
                        raf = new RandomAccessFile("/data/data/com.yydcdut.duothread/lala.exe", "rwd");
                        raf.setLength(length);
                        raf.close();
                        // 假设是3个线程去下载资源
                        // 平均每一个线程下载的文件大小
                        int blockSize = length / threadCount;
                        for (int threadId = 1; threadId <= threadCount; threadId++) {
                            // 第一个线程下载的开始位置
                            int startIndex = (threadId - 1) * blockSize;
                            int endIndex = threadId * blockSize;
                            if (threadId == threadCount) {
                                // 最后个线程下载的长度弄得稍微大一点
                                endIndex = length;
                            }
                            System.out.println("线程:" + threadId + "---下载:"
                                    + startIndex + "--->" + endIndex);
                            // 开始下载
                            new DownloadThread(path, threadId, startIndex,
                                    endIndex).start();
                        }
                    } else {
                        System.out.println("服务器错误!!!");
                        Message msg = new Message();
                        msg.what = SERVER_ERROR;
                        handler.sendMessage(msg);
                    }
                } catch (MalformedURLException e1) {
                    // TODO 自动生成的 catch 块
                    e1.printStackTrace();
                } catch (Exception e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }
                super.run();
            }
        }.start();
    }
复制代码

httpUrlConnection先得到要下载的文件的大小,然后将这个文件分别分为几份(我这里是开启三个线程下载,所以平均分了3份)。还有先建立一个与下载大小一样的文件,通过RandomAccessFile实现。

下载子线程                                                                                   

复制代码
public class DownloadThread extends Thread {
        private int threadId;
        private int startIndex;
        private int endIndex;
        private String path;

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

        @Override
        public void run() {

            File tempFile = new File("/data/data/com.yydcdut.duothread/" + threadId + ".txt");
            if (tempFile.exists() && tempFile.length() > 0) {
                try {
                    FileInputStream fis = new FileInputStream(tempFile);
                    byte[] temp = new byte[1024];
                    int leng = fis.read(temp);
                    String downLoadLen = new String(temp, 0, leng);
                    int downloadlenInt = Integer.parseInt(downLoadLen);

                    int alreadyDowlLoad = downloadlenInt - startIndex;
                    currentProcess += alreadyDowlLoad;
                    startIndex = downloadlenInt;// 修改下载的真实的开始位置
                    fis.close();
                } catch (Exception e) {
                    // TODO 自动生成的 catch 块
                    e.printStackTrace();
                }

            }

            URL url;
            try {
                url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url
                        .openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(5000);
                conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
                        + endIndex);
                System.out.println("线程真实下载:" + threadId + "下载----" + startIndex
                        + "---->" + endIndex);
                int code = conn.getResponseCode();// 从服务器请求全部资源200 如果请求部分资源206
                System.out.println("threadId--->" + threadId + "----code:"
                        + code);
                InputStream is = conn.getInputStream();// 设置请求位置,返回是当前位置对应的文件输入流
                // 随机写文件的时候从那个位置开始写
                RandomAccessFile raf = new RandomAccessFile("/data/data/com.yydcdut.duothread/lala.exe",
                        "rwd");
                raf.seek(startIndex);
                int len = 0;
                byte[] buffer = new byte[1024];
                int total = 0;// 记录下载多少了
                while ((len = is.read(buffer)) != -1) {
                    total += len;
                    raf.write(buffer, 0, len);
                    // System.out.println("线程:"+threadId+"下载了total:"+total);
                    RandomAccessFile file = new RandomAccessFile("/data/data/com.yydcdut.duothread/"
                            + threadId + ".txt", "rwd");
                    file.write((total + startIndex + "").getBytes());
                    file.close();
                    // 更新进度条
                    synchronized (MainActivity.this) {
                        currentProcess += len;
                        pb.setProgress(currentProcess);
                        Message msg = new Message();
                        msg.what = UPDATE_TEXT;
                        handler.sendMessage(msg);
                    }
                }
                is.close();
                raf.close();
                System.out.println("线程" + threadId + "下载完毕............");
            } catch (Exception e) {
                // TODO 自动生成的 catch 块
                e.printStackTrace();
            } finally {
                threadFinish();
            }
            super.run();
        }
    }
复制代码

在这里建立了一个txt文件,目的就是将下载到哪的数据存进去,如果网断了再下载的话,实现断点下载,那么下次下载就可以从这里读取数据,然后在写入文件,就不需要重头再分配大小下载了。这里还用到了线程同步去更新进度条。

删除临时txt文件threadFinish                                                      

复制代码
private synchronized void threadFinish() {
        runningThread--;
        if (runningThread == 0) {
            for (int i = 1; i <= 3; i++) {
                File file = new File("/data/data/com.yydcdut.duothread/" + i + ".txt");
                file.delete();
            }
            System.out.println("文件下载完毕,删除所有的下载记录。。。");
            Message msg = new Message();
            msg.what = DOWN_LOAD_FINISH;
            handler.sendMessage(msg);
        }
    }
复制代码

Handler                                                                                    

复制代码
private Handler handler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case DOWN_LOAD_ERROR:
                Toast.makeText(getApplicationContext(), "下载失败", 0).show();
                break;
            case SERVER_ERROR:
                Toast.makeText(getApplicationContext(), "服务器 错误,下载失败", 0)
                        .show();
                break;
            case DOWN_LOAD_FINISH:
                Toast.makeText(getApplicationContext(), "文件下载完毕", 0).show();
                break;
            case UPDATE_TEXT:
                et_path.setText("当前进度:" + pb.getProgress() * 100 / pb.getMax());
                break;
            }

            super.handleMessage(msg);
        }

    };
复制代码

我是天王盖地虎的分割线                                                               

源代码:http://pan.baidu.com/s/1dD1Qx01

MutilDownLoader.zip(JAVA)

多线程下载.zip(Android)




本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3796197.html,如需转载请自行联系原作者

相关文章
|
4月前
|
数据采集 Java API
Jsoup库能处理多线程下载吗?
Jsoup库能处理多线程下载吗?
|
2月前
|
JavaScript 前端开发 Android开发
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
97 13
【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
1月前
|
JavaScript Linux 网络安全
Termux安卓终端美化与开发实战:从下载到插件优化,小白也能玩转Linux
Termux是一款安卓平台上的开源终端模拟器,支持apt包管理、SSH连接及Python/Node.js/C++开发环境搭建,被誉为“手机上的Linux系统”。其特点包括零ROOT权限、跨平台开发和强大扩展性。本文详细介绍其安装准备、基础与高级环境配置、必备插件推荐、常见问题解决方法以及延伸学习资源,帮助用户充分利用Termux进行开发与学习。适用于Android 7+设备,原创内容转载请注明来源。
259 76
|
2月前
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
82 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
2月前
|
数据采集 JavaScript Android开发
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
82 7
【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
|
4月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
5月前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
6月前
|
Java 程序员 开发工具
Android|修复阿里云播放器下载不回调的问题
虽然 GC 带来了很多便利,但在实际编码时,我们也需要注意对象的生命周期管理,该存活的存活,该释放的释放,避免因为 GC 导致的问题。
73 2
|
7月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
226 15
一个Android App最少有几个线程?实现多线程的方式有哪些?

热门文章

最新文章