多线程下载----Activity

多线程下载
Activity



  • 多线程下载
    • 多线程下载:
      平分服务器中的文件,如果平分不了,最后多余的字节给最后一个线程下载。每个线程只下载自己所对应的服务器资源,使用RandomAccessFile下载到本地指定位置,最后所有线程都下载完了该文件就是一个完整的文件。
      多线程下载不会超过单线程下载速度,不会超过最大带宽
  • 多线程下载步骤
    1. 开启网络获取服务器文件的总长度 totalSize;
int totalSize = new URL("http://192.168.82.52:8080/Day08/Deep.mp3")
                .openConnection().getContentLength();
  1. 确定要开启几个线程,一般线程个数是CPU核数 + 1
int threadCount = Runtime.getRuntime().availableProcessors();
  1. 计算每个线程下载的范围 [startIndex , endIndex];平均字节:avgSize,
int avgSize = totalSize / threadCount;


        for (int i = 1; i <= threadCount; i++) {
            int startIndex = avgSize * (i - 1);
            int endIndex = avgSize * i - 1;
            if (i == 3) {
                endIndex = totalSize - 1;
            }
            // 5创建子线程对象
            MyThread mThread = new MyThread(i, startIndex, endIndex,
                    "http://192.168.82.52:8080/Day08/Deep.mp3",
                    "D:\\ceshi\\Deep.mp3");
            mThread.start();


        }
    }
  1. 自定义线程类,然后创建各个线程,在线程的构造函数中传入参数
static class MyThread extends Thread {
        private int id;//线程名
        private int startIndex;//开始的索引
        private int endIndex;//结束的索引
        private String urlpath;//下载的地址
        private String targePath;//下载的位置以及文件名


        // 创建一个构造方法,来创建线程
        public MyThread(int id, int startIndex, int endIndex, String urlpath,
                String targePath) {
            this.id = id;
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.urlpath = urlpath;
            this.targePath = targePath;
        }
  1. 开启各个子线程开始下载各自的任务–>3.5

  2. 让各个子线程将字节写入各自的范围
    具体步骤:

    • 获取网络请求

      HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(urlpath).openConnection();
    • 设置请求部分属性setRequestProperty(“range”,”bytes”+start+”-“+end);状态码==206

      httpURLConnection.setRequestProperty("Range", "bytes="+ startIndex + "-" + endIndex);
    • 判断状态码是否==206

      • 是:获取服务器返回的流getInputstream

        InputStream inputStream = httpURLConnection.getInputStream();
        • RandomAccessFile写文件(即可度又可写),如果文件不存在就创建一个即可读又可写的文件(文件路径,属性rw)
        RandomAccessFile rFile = new RandomAccessFile(targePath,"rw");
        • 默认情况下,rFile 指向文件第0个角标,需要移动指针到指定位置,调用.seek(设置的角标值)
        rFile.seek(startIndex);
        • 创建一个字节数据写入指定文件
            int len;
            byte[] arr = new byte[1024];
            while ((len = inputStream.read(arr)) != -1) {
                rFile.write(arr, 0, len);
            }
            System.out.println("线程" + id +"传了"+(endIndex-startIndex)+ "   完成了");
        
            // 释放资源
            inputStream.close();
            rFile.close();
        • 否:返回状态码不对

多线程断点下载

跟多线程下载步骤一样,只是在子线程的构造方法中添加了临时文件的开始标签newStartIndex,和临时记录线程下载的字节数据的文件temFile

//增加的属性
private int newStartIndex;//临时文件的开始标签
private File temFile;//临时文件
//在构造方法中把字节写入临时文件,每次断点后都会从新标签开始写
temFile = new File("D:\\ceshi\\"+id+".txt");
    try {
        BufferedReader br = new BufferedReader(new FileReader(temFile));
        String string = br.readLine();
        newStartIndex = Integer.parseInt(string);//获取断点读取的字节数,断点新开始的索引
        br.close();
    } catch (Exception e) {

        e.printStackTrace();
    }

//在run方法中读取临时文件存的数据,开始写文件,直到文件下载完成
//注意请求网络时,设置请求部分属性setRequestProperty("Range","bytes"+newstartINdex+"-"+end),是 新书签newstartINdex - 最后的索引,不是开始索引
connection.setRequestProperty("Range", "bytes="+newStartIndex+"-"+endIndex);


while((len=inputStream.read(arr))!=-1){
    rFile.write(arr,0,len);
    total+=len;
    FileWriter fw = new FileWriter(temFile);
    fw.write(newStartIndex+total+"");//写的是开始的坐标加新获取的数据
    fw.close();
//  打印百分比
//  (newStartIndex-startIndex之前下载的字节数+1+total//新下载的字节数???)/endIndex - startIndex +1//总共下载的字节数)
    float percent = (newStartIndex-startIndex+1+total+0.f)/(endIndex - startIndex +1);
}
    System.out.println("完成了"+this);
    inputStream.close();
    rFile.close();
                }

RandomAcessFile可以进行读和写
- 方法:
- .seek();设置读写开始的索引
- .write():跟普通流流一样可以进行写
- .close();用完要释放资源


xUtils介绍

四大模块:
- DbUtils模块:操作数据库。一行代码进行增删改查
- orm: object relation mapping:对象关系映射
- ViewUtils模块:资源和事件的绑定。一行代码进行findViewById
- IOC:控制反转框架(依赖注入)
- HttpUtils模块:网络请求
- BitmapUtils模块:图片加载


xUtils练习





面试题:

Activity可以传那些数据?
- 8种基本数据类型(以及数组形式)
- String类型
- 实现序列化的接口

什么是Activity?
Activity是Android中四大组件之一,提供了窗口供用户与手机进行交互,比如拨打电话/发短信/照相/浏览网页,只要是手机屏幕上能看到的东西都依托于Activity。(一个界面)



问题
  1. 多线程下载,循环子线程时,for的判断条件是i<=线程的个数,int i= 1 ;一般都是从1开始,计算公式的时候相匹配

    thread1 = [3 * 0 , 3 - 1];
    thread2 = [3 * 1 , 2*3-1];
    thread3 = [3 * 2 , 3*3-1];
    threadn = [avgSize * (n-1) , avgSize*n-1]
    if(n == 3){
            threadn = [avgSize*(n-1),totalSize-1]
    }
    
  2. 理不清RandomAccessFile(),用的时候用成,———–在写数据是用 RandomAccessFile() 来写数据

  3. 获取endIndex时,当是最后一个线程时 endIndex= 文件总长度-1;
  4. 获取网络请求时,用的是HttpURLConnection,容易导错包
  5. 在断点下载时,设置请求部分属性时,是新书签,而不是开始书签

    connection.setRequestProperty("Range", "bytes="+newStartIndex+"-"+endIndex);
    
  6. 断点下载时.断点后开始写入的是新书签加上在下次断点前读取的数据

    fw.write(newStartIndex+total+"");
  7. 不明白设置请求部分请求为什么那样写?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值