Android 多线程断点下载(非原创)

1.服务器的CPU分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源,这里在客户端开启多个线程来从服务器下载资源

2.fragment_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!-- 点击下载按钮 -->

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="download"
        android:text="开始下载" />
    <!-- 进度条 -->

    <ProgressBar
        android:id="@+id/pb_bar"
        style="@android:style/Widget.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <!-- 显示进度 如: 5% -->

    <TextView
        android:id="@+id/tv_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#CC5599"
        android:textSize="24sp" />

</LinearLayout>

3.MainActivity.java

package com.example.phonemultithreaddownload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {
    // 文件名字
    String fileName = "ESurfing_V2.1.exe";
    // 路径
    String path = "http://192.168.1.66:8080/" + fileName;
    // 线程的个数,越多下载的越快
    int threadCount = 3;
    // 线程下载完毕的个数
    private static int finishThreadCount = 0;
    // 进度条
    ProgressBar pb_bar;
    // 显示进度
    TextView tv_progress;
    // 当前下载的进度
    int totalProgress = 0;
    // 消息处理器
    Handler handler = new Handler() {
    public void handleMessage(android.os.Message msg) {
        // 刷新TextView,注意:pb_bar.getProgress返回的值会超出int范围,结果可能为负数,需要强转为long
        tv_progress.setText((long) pb_bar.getProgress() * 100 / pb_bar.getMax() + " %");
    };
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_main);
    //加载进度条
    pb_bar = (ProgressBar) findViewById(R.id.pb_bar);
    //加载进度文本
    tv_progress = (TextView) findViewById(R.id.tv_progress);
    }

    public void download(View v) {// 下载
    Thread t = new Thread() {
        @Override
        public void run() {
        try {
            URL url = new URL(path);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(5000);
            con.setReadTimeout(5000);
            con.setRequestMethod("GET");
            if (con.getResponseCode() == 200) {
            // 拿到请求资源文件的大小
            int length = con.getContentLength();
            // 设置进度条最大值
            pb_bar.setMax(length);
            File file = new File(fileName);
            // 生成临时文件
            RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/" + file, "rwd");
            //设置临时文件的大小
            raf.setLength(length);
            raf.close();
            //求出每个线程平均下载的字节数
            int size = length / threadCount;
            for (int i = 0; i < threadCount; i++) {
                //开始的位置
                int startIndex = i * size;
                //结束的位置
                int endIndex = i * size + size - 1;
                //如果是最后一个线程,开始的位置确定,但是结束的位置是不确定的,直接设为文件的长度即可
                if (i == threadCount - 1) {
                endIndex = length;
                }
                System.out.println("ID : " + i + startIndex + "~" + endIndex + " , " + (endIndex - startIndex + 1));
                //创建线程并启动
                 new DownLoadThread(startIndex, endIndex, i + 1, path).start();
            }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        }
    };
    t.start();
    }

    class DownLoadThread extends Thread {
    //开始下载的位置
    private int startIndex;
    //结束下载的位置
    private int endIndex;
    //线程的ID
    private int threadId;
    //下载的资源路径
    private String path;

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

    @Override
    public void run() {
        try {
        URL url = new URL(path);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setConnectTimeout(5000);
        con.setReadTimeout(5000);
        con.setRequestMethod("GET");
        /*
         * 先判断是否保存了上次下载的字节数
         */
        File progessFile = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
        if (progessFile.exists()) {
            // 如果文件存在,说明不是第一次下载,修改下载的开始位置
            BufferedReader br = new BufferedReader(new FileReader(progessFile));
            //读取一行
            int newIndex = Integer.parseInt(br.readLine());
            //修改开始的位置
            startIndex = startIndex + newIndex;
            //修改进度条的值
            totalProgress += newIndex;
            System.out.println(threadId + " , 上次下载了 " + newIndex);
            br.close();
        }
        // 设置本次http所请求的区间
        con.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
        // 请求部分数据的响应码是206
        if (con.getResponseCode() == 206) {
            RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory() + "/" + fileName, "rwd");
            // 把文件的写入位置移动至startIndex位置
            raf.seek(startIndex);
            InputStream is = con.getInputStream();
            int len = -1;
            int total = 0;
            byte[] buf = new byte[1024];
            while ((len = is.read(buf)) != -1) {
            //将读取到的数据i写入文件中
            raf.write(buf, 0, len);
            //记录该线程一共下载了多少
            total += len;
            System.out.println("线程" + threadId + "下载了" + total);
            //更改进度条的值
            totalProgress += len;
            // 设置进度
            pb_bar.setProgress(totalProgress);
            // 显示进度,发送空消息,携带进度的值
            handler.sendEmptyMessage(totalProgress);
            RandomAccessFile processRaf = new RandomAccessFile(progessFile, "rwd");
            processRaf.write((total + "").getBytes());
            processRaf.close();
            }
            System.out.println(threadId + "下载完成了------------------------------------------");
            raf.close();
            // 删除缓存文件
            finishThreadCount++;
            System.out.println("准备删除文件" + threadId + "   finishThreadCount = " + finishThreadCount);
            synchronized (DownLoadThread.class) {
            if (finishThreadCount == threadCount) {
                for (int i = 0; i < threadCount; i++) {
                File tempFile = new File(Environment.getExternalStorageDirectory(), i + 1 + ".txt");
                System.out.println("删除" + (i + 1) + ".txt文件");
                tempFile.delete();
                }
                finishThreadCount = 0;
                // 资源下载完毕,有可能出现99%的情况,手动改为100%
                pb_bar.setProgress(pb_bar.getMax());
            }
            }
        }
        } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
    }
    }

}

4.添加权限,网络权限和网SD卡写入的权限

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

5.效果如下:

时间: 2024-12-16 17:54:05

Android 多线程断点下载(非原创)的相关文章

Android 多线程断点下载源码

源码下载地址   http://download.csdn.net/detail/kiduo08/7709391 Android 多线程断点下载源码

Android 学习之--android多线程断点下载

我们平时都用"迅雷"下载软件,当下载到一半的时候突然断网,下次开启的时候能够从上次下载的地方继续下载,而且下载速度很快,那么这是怎么做到的呢! 其实它的“快”其实就是多线程的下载实现的,断点下载的原理是将每次下载的字节数存取下来,保证存取的子节点跟下载的同步,并在用户下次下载的时候自动读取 存储点,并以存储点为开始值继续下载.那么android里面如何实现这么断点的下载呢? 在res的布局文件里面先画一个带有进度条的下载界面 activity_main.xml <LinearLa

Android 多线程断点下载

package com.itheima.mutiledownloader; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader;

Android多线程断点下载的代码流程解析

Step 1:创建一个用来记录线程下载信息的表 创建数据库表,于是乎我们创建一个数据库的管理器类,继承SQLiteOpenHelper类 重写onCreate()与onUpgrade()方法 DBOpenHelper.java: public class DBOpenHelper extends SQLiteOpenHelper { public DBOpenHelper(Context context) { super(context, "downs.db", null, 1); }

Android/java http多线程断点下载(附源码)

先看下项目结构: http多线程断点下载涉及到 数据库,多线程和http请求等几个模块,东西不是很多,想弄清楚也不是很困难,接下来我和大家分享下我的做法. 一.先看MainActivity.java 成员变量,主要是一些下载过程的变量和handler private String path = "http://192.168.1.3:8080/wanmei/yama.apk"; private String sdcardPath; private int threadNum = 5;

Android实现多线程断点下载

本案例在于实现文件的多线程断点下载,即文件在下载一部分中断后,可继续接着已有进度下载,并通过进度条显示进度.也就是说在文件开始下载的同时,自动创建每个线程的下载进度的本地文件,下载中断后,重新进入应用点击下载,程序检查有没有本地文件的存在,若存在,获取本地文件中的下载进度,继续进行下载,当下载完成后,自动删除本地文件. 1. 定义布局文件需要用到的属性名及内容 2. 设置用户的Internet权限和关于SD卡的权限 <span style="font-size:14px;">

android 多线程断点续传下载 四 - 仿下载助手

我们先一起简单回顾下它的基本原理. http://blog.csdn.net/shimiso/article/details/6763664  android 多线程断点续传下载 一 http://blog.csdn.net/shimiso/article/details/6763986  android 多线程断点续传下载 二 http://blog.csdn.net/shimiso/article/details/8448544  android 多线程断点续传下载 三 界面效果 线程池 T

多线程断点下载原理(java代码实例演示)

其实多线程断点下载原理,很简单的,那么我们就来先了解下,如何实现多线程的断点下载,首先:你必须明白第一点,那么就是,什么是多线程下载,该知识点可以查看本博客上一篇文章,Android之多线程下载原理,断点下载呢,其实就是在这个的基础之上添加了一些东西,那么添加了什么东西了,现在来做一个详细的了解. 1.在下载的过程中,边下载,变用一个文件来记录下载的位置,也就是下载了多少的数据 1.创建文件 2.记录下载多少数据 3.存储数据 2.第二次下载的时候,就去读取文件中是否存有数据,读取上次下载的位置

Android多线程断点续传下载

这个月接到一个项目,要写一个像360助手一样的对于软件管理的APP:其中,遇到了一个问题:多线程断点下载 这个 ,由于之前没有写过这方面的应用功能.所以,不免要自学了.然后就在各个昂站上收索并整理了一下.跟大家分享一下,也能加深我在这方面的理解. 什么是多线程下载? 多线程下载其实就是迅雷,BT一些下载原理,通过多个线程同时和服务器连接,那么你就可以榨取到较高的带宽了,大致做法是将文件切割成N块,每块交给单独一个线程去下载,各自下载完成后将文件块组合成一个文件,程序上要完成做切割和组装的小算法