zoukankan      html  css  js  c++  java
  • 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.效果如下:

  • 相关阅读:
    js,jQuery 排序的实现,网页标签排序的实现,标签排序
    SQL不规则排序,ORDER BY 不规则排序,case的使用
    XML methods are not allowed in a GROUP BY clause.XML不允许使用排序方法的处理
    DropDownList设置选定项,设置选择项,最安全的方法
    js 字符串转成货币格式, js转货币
    排名进入20000纪念
    jQuery对象和Dom对象互相转换
    屏蔽页面JS错误,拦截页面JS错误的代码,js禁止跳出错误提示
    枚举,以及中文对应解释
    insert into插入表,插入多条数据,sql插入表,插入多条数据,数据库插入表,插入多条数据
  • 原文地址:https://www.cnblogs.com/biao2015/p/5094676.html
Copyright © 2011-2022 走看看