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

相关文章
|
Android开发
Android中 Download Manager系统下载管理器在Android 10系统中无法使用的情况
Android中 Download Manager系统下载管理器在Android 10系统中无法使用的情况
333 0
|
算法 Java Android开发
Android模拟多线程下载
Android模拟多线程下载
84 0
|
缓存 监控 Shell
Android--adb命令详解
ADB,即 Android Debug Bridge,它是 Android 开发/测试人员不可替代的强大工具,也是 Android 设备玩家的好玩具。
2550 0
|
Java Android开发 API
|
缓存 调度 Android开发
|
算法 Android开发
Android--多线程断点续传
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/78057591 什么是多线程下载? 多线程下载其实就是迅雷,BT一些下载原理,通过多个线程同时和服务器连接,那么你就可以榨取到较高的带宽了,大致做法是将文件切割成N块,每块交给单独一个线程去下载,各自下载完成后将文件块组合成一个文件,程序上要完成做切割和组装的小算法。
1358 0
|
安全 Shell Linux
Android--手机一键Root原理分析
Root的由来        什么是Root?Root本身是指Linux系统的root帐户,该帐户拥有整个系统至高无上的权利,系统中的所有对象它都可以操作,对于Android手机用户来说的Root是指拥有Root权限,一般情况下,手机厂商出于安全考虑会关闭手机的Root权限,手机系统是运行在普通用户权限下的,用户是无法操作系统中的文件与数据的。
1716 0
|
Android开发 容器 Shell
Android--视频播放器
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/chaoyu168/article/details/51179636 SurfaceView 先来介绍一下大部分软件如何解析一段视频流。
930 0