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 调度 Android开发
构建高效Android应用:探究Kotlin多线程编程
【2月更文挑战第17天】 在现代移动开发领域,性能优化一直是开发者关注的焦点。特别是在Android平台上,合理利用多线程技术可以显著提升应用程序的响应性和用户体验。本文将深入探讨使用Kotlin进行Android多线程编程的策略与实践,旨在为开发者提供系统化的解决方案和性能提升技巧。我们将从基础概念入手,逐步介绍高级特性,并通过实际案例分析如何有效利用Kotlin协程、线程池以及异步任务处理机制来构建一个更加高效的Android应用。
35 4
|
1月前
|
API 数据库 Android开发
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第14天】随着移动设备性能的日益强大,用户对应用程序的响应速度和流畅性要求越来越高。在Android开发中,合理利用多线程技术是提升应用性能的关键手段之一。Kotlin作为一种现代的编程语言,其协程特性为开发者提供了更为简洁高效的多线程处理方式。本文将深入探讨使用Kotlin进行Android多线程编程的最佳实践,包括协程的基本概念、优势以及在实际项目中的应用场景和性能优化技巧,旨在帮助开发者构建更加高效稳定的Android应用。
|
3月前
|
Java 调度 数据库
Android 性能优化: 如何进行多线程编程以提高应用性能?
Android 性能优化: 如何进行多线程编程以提高应用性能?
46 0
|
4月前
|
XML Java Android开发
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
132 0
|
6天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
17天前
|
安全 Linux API
Android进程与线程
Android进程与线程
18 0
|
1月前
|
Shell 开发工具 Android开发
ADB 下载、安装及使用教程:让你更好地管理 Android 设备
ADB 下载、安装及使用教程:让你更好地管理 Android 设备
458 2
|
1月前
|
Java Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第17天】 随着移动设备性能的不断提升,用户对应用的响应速度和稳定性要求越来越高。在Android开发中,Kotlin语言以其简洁、安全的特点受到开发者青睐。然而,面对复杂的多线程任务,如何有效利用Kotlin进行优化,以提升应用性能,是本文探讨的重点。通过分析Kotlin并发工具的使用场景与限制,结合实例演示其在Android开发中的实践,旨在为开发者提供实用的多线程处理指南。
|
1月前
|
Android开发 对象存储
OSS对象储存android开发进行下载到本地文件时异步操作失效
android vivo80使用官方示例代码进行文件下载,但是使用oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>()时onSuccess和onFailure不执行
|
4月前
|
XML Java 调度
Android App网络通信中通过runOnUiThread快速操纵界面以及利用线程池Executor调度异步任务实战(附源码 简单易懂)
Android App网络通信中通过runOnUiThread快速操纵界面以及利用线程池Executor调度异步任务实战(附源码 简单易懂)
30 0