Android 网络学习之使用多线程下载,支持断点续传

既然本节是学习如何使用多线程下载,那我们先要明白什么是多线程下载,在搞明白什么是多线程下载之前,需要先知道什么是单线程下载。

上图就是说明了单线程下载的原来,因此单线程下载速度很慢,因为只有一个任务在干活。

这样的话,3个线程下载一个文件,总比1个线程一个文件的速度要快。所以多线程下载数据的速度就快。

既然知道了多线程的下载原理,那我们就分析多个线程是如何下载数据,以及如何保存数据的。

知道多线程下载的原理,以及每个线程如何存放数据后,那就开始写代码。

1: 当然先要获取该数据的大小了,这样才知道给每个线程分配多大的下载量

我在服务器上下载一个exe文件名为:wireshark.exe

先从服务器上获取该文件的大小,并计算每个线程应该下载的大小区间

public void downloade(View v)
    {
    	Thread thread = new Thread()
    	{
    		//服务器地址
    		String path = "http://192.168.1.123:8080/Wireshark.exe";
    		@Override
    		public void run() {
    			try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setRequestMethod("GET");
					conn.setReadTimeout(5000);
					conn.setReadTimeout(5000);

					if(conn.getResponseCode() == 200)
					{
						//获取数据的总大小
						int length = conn.getContentLength();
						//每个线程的大小
						int size = length / threadCount;

						for(int i = 0; i < threadCount; i++)
						{
							int startIndex = i * size;
							int endIndex = (i + 1)*size - 1;
							//最后一个线程的结束地址为文件总大小-1
							if(i == threadCount - 1)
							{
								endIndex = length - 1;
							}

							System.out.println("线程" + i + "的下载区间为:" + startIndex + "---" + endIndex);
						}

					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
    		}
    	};

    	thread.start();
    }

打印结果为:

可以看到大小是正确的。总的大小为29849552大小

2: 既然已经给每个线程分好了下载区间,那我们就开始下载

在下载开始时,先要在存储设备上分配一个个下载文件一样大小的临时文件,这样可以避免下载过程中出现存储不够。

System.out.println("线程" + i + "的下载区间为:" + startIndex + "---" + endIndex);
							//开启threadCount去下载数据
							new downloadThread(startIndex, endIndex, i).start();
class downloadThread extends Thread{
    	int startIndex;//开始位置
    	int endIndex;//结束位置
    	int threadId;//线程Id

    	//构造方法
		public downloadThread(int startIndex, int endIndex, int threadId) {
			super();
			this.startIndex = startIndex;
			this.endIndex = endIndex;
			this.threadId = threadId;
		}

		@Override
		public void run() {
			//这次需要请求要下载的数据了
			URL url;
			try {
				url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod("GET");
				conn.setReadTimeout(5000);
				conn.setReadTimeout(5000);
				//设置本次HTTP请求数据的区间
				conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
				//请求部分数据,返回码为206
				if(conn.getResponseCode() == 206)
				{
					//此时取到的流里的数据只有上面给定区间的大小
					InputStream is = conn.getInputStream();
					byte[] b = new byte[1024];
					int len = 0;
					int total = 0;

					//再次打开临时文件
					File file = new File(Environment.getExternalStorageDirectory(), filename);
					RandomAccessFile raf = new RandomAccessFile(file, "rwd");
					//把文件的写入位置指定到startindex
					raf.seek(startIndex);

					while((len = is.read(b)) != -1)
					{
						raf.write(b, 0, len);
						total += len;
						System.out.println("线程" + threadId + "下载了" + total);
					}

					System.out.println("线程" + threadId + "---------------下载完毕-------------------");
					raf.close();
				}

			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

    }

从打印中可以看到是可以下载成功的。

3: 既然下载东西,对用户来说就的知道下载的进度。我们使用进度条显示现在的进度

设置最大进度

//获取数据的总大小
						int length = conn.getContentLength();

						//设置进度条的最大值
						pBar.setMax(length);

						//每个线程的大小
						int size = length / threadCount;

这是当前的进度

						raf.write(b, 0, len);
						total += len;
						System.out.println("线程" + threadId + "下载了" + total);

						//设置当前进度,是3个线程的总和
						currProgress += len;
						pBar.setProgress(currProgress);

再设置文本显示,当前比例。要使用消息来更新UI

	Handler handler = new Handler()
	{
		public void handleMessage(android.os.Message msg)
		{
			//显示下载比例,转为为long型,int的时候有时候不够大
			tView.setText((long)pBar.getProgress() * 100 / pBar.getMax() + "%");
		};
	};

效果图:

接下来实现断点续传:

			File bakFile = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
			try {
				//判断文件是否存在
				if(bakFile.exists())
				{
					FileInputStream fis = new FileInputStream(bakFile);
					BufferedReader bReader = new BufferedReader(new InputStreamReader(fis));
					//从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
					int lastProgress = Integer.parseInt(bReader.readLine());
					startIndex += lastProgress;

					//把上次下载的进度显示至进度条
					currProgress += lastProgress;
					pBar.setProgress(currProgress);

					//发送消息,让主线程刷新文本进度
					handler.sendEmptyMessage(1);
					fis.close();
				}

在下载时候,先需要创建配置文件,防止下载过程中某些原因导致停止下载,当后续接着下载时,还是会用上次下载的地方接着下载

					while((len = is.read(b)) != -1)
					{
						raf.write(b, 0, len);
						total += len;
						System.out.println("线程" + threadId + "下载了" + total);

						//设置当前进度,是3个线程的总和
						currProgress += len;
						pBar.setProgress(currProgress);
						//通过发送消息,更新文本。而进度条不需要通过发消息刷新UI,因为进度条本身就是在别的任务中使用的
						handler.sendEmptyMessage(1);

						//将当前的下载进度保存到配置文件中
						RandomAccessFile bakRaFile = new RandomAccessFile(bakFile, "rwd");
						bakRaFile.write((total + "").getBytes());
						bakRaFile.close();
					}

可以正常的支持断点连续下载

下载的文件可以正常运行,我将下载文件转为feiq了,因为wireshark有点大

http://download.csdn.net/detail/longwang155069/8991785

源码下载地址

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-10 08:22:56

Android 网络学习之使用多线程下载,支持断点续传的相关文章

Android(十五)多线程下载包括断点续传

1.多线程下载,java程序 package com.itheima.download; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; imp

android开发笔记之多线程下载及断点续传

今天我们来接触一下多线程下载,当然也包括断点续传,我们可以看到 很多下载器,当开通会员的时候下载东西的速度就变得快了许多,这是为什么呢?这就是跟今天讲的多线程有关系了,其实就是多开了几个线程一起下载罢了.当然真正的多线程下载要比这个复杂,要考虑很多问题. 做个不恰当的比喻: 假如我们把一个服务器上的文件看作是一个水缸里的水的话,那么多线程下载就相当于从水缸上打了多个小孔,然后塞进去小管道进行抽水.呵呵,也许这个比喻不够准确. 效果: 这里下载的是本地服务器上的文件,你们可以下载网络上的一些文件.

【幻化万千戏红尘】qianfengDay27-HttpURLConnection,OkHttpClient,,多线程下载且断点续传基础学习:

课程回顾: Servlet:java语言开发的运行在服务器上的开发步骤:1.创建Servlet类2.重写doGet或doPost方法3.运行在服务器 生命周期:1.初始化2.服务3.销毁 URL:统一资源定位符,网址openConnection 今日内容:Http协议:超文本传输协议常用方式:1.HttpURLConnection2.okHttp HttpURLConnection的使用步骤:1.创建URL对象---URL url=new URL("网址");2.获取连接对象--Htt

Nginx支持用户多线程下载和断点续传

RFC2616规范中定义了range协议,它给出一种规则使得客户端可以再一次请求中只下载完整文件的一部分,这样就支持客户端在开启多线程的同时下载一份文件,其中每个线程仅下载文件的一部分,最后组合成完整的文件,range也支持断点续传,只要客户端记录了已下载部分文件偏移量,就可以要求服务器从断点处发送文件之后的内容. Nginx对range协议支持的非常好,因为range协议主要增加了一些HTTP头部处理流程,以及发送文件时的偏移量处理.Nginx设计了HTTP过滤模块,每个请求可以由许多HTTP

Android开发--多线程下载加断点续传

文件下载在App应用中也用到很多,一般版本更新时多要用的文件下载来进行处理,以前也有看过很多大神有过该方面的博客,今天我也自己来实践一下,写的一般,还请大家多提意见,共同进步.主要思路: 1.多线程下载: 首先通过下载总线程数来划分文件的下载区域:利用int range = fileSize / threadCount:得到每一段下载量:每一段的位置是i * range到(i + 1) * rang  - 1,注意最后一段的位置是到filesize - 1: 通过Http协议的Range字段实现

浅谈Android和java中的多线程下载

为什么要使用多线程下载呢? 究其原因就一个字:"快",使用多线程下载的速度远比单线程的下载速度要快,说到下载速度,决定下载速度的因素一般有两个: 一个是客户端实际的网速,另一个则是服务端的带宽.我们经常使用的是单线程下载,也就是下载一个文件就是开启一个线程去请求下载资源. 这里我们不考虑客户端实际网速因素,因为这个因素多变,不好控制.我们主要考虑的因素就是服务端的带宽.那么服务端是如何给每个客户端分配 它的下载带宽的呢???它分配的原理大致是这样的,服务端只会给请求它的每个线程平均分配

Android 多线程下载,断点续传,线程池

你可以在这里看到这个demo的源码: https://github.com/onlynight/MultiThreadDownloader 效果图 这张效果图是同时开启三个下载任务,限制下载线程数量的效果图. 多线程下载原理 多线程下载的原理就是将下载任务分割成一个个小片段再将每个小片段分配给各个线程进行下载. 例如一个文件大小为100M,我们决定使用4个线程下载,那么每个线程下载的大小即为25M,每个线程的起始以及结束位置依次如下: 0: 0-25M 1: 25-50M 2: 50-75M 3

自己写的一个简单的迅雷下载支持断点续传

当我学习了网络线程,就自己仿照迅雷下载写了一个下载器,支持断点续传 我用的是SWT插件做的界面 界面 package com.yc.xunlei; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.Arra

google obb(三)从自己cdn上下载(支持断点续传)

支持断点续传 参考网址 https://www.twblogs.net/a/5b8b35ad2b717718832e0bb6/zh-cn https://blog.csdn.net/AnYuanLzh/article/details/70848442 当然还需要判断 网络是否连接.当前非wifi提示是否手机下载.obb下载完毕校验obb是否正确 你可能还需要了解: 修改Unity导出Android工程启动时黑屏,启动时间过长 原文地址:https://www.cnblogs.com/wangle