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,如需转载请自行联系原作者

相关文章
|
1月前
|
数据采集 Java API
Jsoup库能处理多线程下载吗?
Jsoup库能处理多线程下载吗?
|
1月前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
2月前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
3月前
|
Java 程序员 开发工具
Android|修复阿里云播放器下载不回调的问题
虽然 GC 带来了很多便利,但在实际编码时,我们也需要注意对象的生命周期管理,该存活的存活,该释放的释放,避免因为 GC 导致的问题。
49 2
|
3月前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
74 4
|
4月前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
156 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
4月前
|
Java Android开发 UED
🧠Android多线程与异步编程实战!告别卡顿,让应用响应如丝般顺滑!🧵
在Android开发中,为应对复杂应用场景和繁重计算任务,多线程与异步编程成为保证UI流畅性的关键。本文将介绍Android中的多线程基础,包括Thread、Handler、Looper、AsyncTask及ExecutorService等,并通过示例代码展示其实用性。AsyncTask适用于简单后台操作,而ExecutorService则能更好地管理复杂并发任务。合理运用这些技术,可显著提升应用性能和用户体验,避免内存泄漏和线程安全问题,确保UI更新顺畅。
144 5
|
4月前
|
API Android开发 iOS开发
安卓与iOS开发中的线程管理对比
【9月更文挑战第12天】在移动应用的世界中,安卓和iOS平台各自拥有庞大的用户群体。开发者们在这两个平台上构建应用时,线程管理是他们必须面对的关键挑战之一。本文将深入探讨两大平台在线程管理方面的异同,通过直观的代码示例,揭示它们各自的设计理念和实现方式,帮助读者更好地理解如何在安卓与iOS开发中高效地处理多线程任务。
|
4月前
|
Java Android开发 开发者
安卓应用开发中的线程管理优化技巧
【9月更文挑战第10天】在安卓开发的海洋里,线程管理犹如航行的风帆,掌握好它,能让应用乘风破浪,反之则可能遭遇性能的暗礁。本文将通过浅显易懂的语言和生动的比喻,带你探索如何优雅地处理安卓中的线程问题,从基础的线程创建到高级的线程池运用,让你的应用运行更加流畅。