版本信息

apply plugin: 'com.android.application'

android {
compileSdkVersion 23
buildToolsVersion "23.0.3" defaultConfig {
applicationId "xidian.dy.com.chujia"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
} dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
}

亲测可用

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="输入url:" /> <EditText
android:id="@+id/url"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout> <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" > <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="输入保存的文件名:" /> <EditText
android:id="@+id/target"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout> <Button
android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载" /> <ProgressBar
android:id="@+id/progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" /> </LinearLayout>

下载工具类

package xidian.dy.com.chujia;

/**
* Created by dy on 2016/6/29.
*/
import android.os.Environment;
import android.os.StrictMode;
import android.util.Log; import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL; /**
* Description:
* 创建ServerSocket监听的主类
* @author jph
* Date:2014.08.27
*/
public class DownUtil
{
/**下载资源的URL**/
private String path;
/**下载的文件的保存位置**/
private String targetFile;
/**需要使用多少线程下载资源**/
private int threadNum;
/**下载的线程对象**/
private DownThread[] threads;
/**下载的文件的总大小**/
private int fileSize; public DownUtil(String path, String targetFile, int threadNum) {
this.path = path;
this.threadNum = threadNum;
// 初始化threads数组
threads = new DownThread[threadNum];
this.targetFile = targetFile;
} public void download() throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setReadTimeout(5*1000);
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
+ "application/x-shockwave-flash, application/xaml+xml, "
+ "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
+ "application/x-ms-application, application/vnd.ms-excel, "
+ "application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.connect();
if(conn.getResponseCode() == 200){
// 得到文件大小
fileSize = conn.getContentLength();
//关闭连接
conn.disconnect();
//计算每个线程下载文件大小
int currentPartSize = fileSize / threadNum;
//创建本地文件 File myfile = new File(Environment.getExternalStorageDirectory(), targetFile);
if(myfile.exists())
myfile.delete();
else
myfile.createNewFile();
RandomAccessFile file = new RandomAccessFile(myfile, "rwd");
// 设置本地文件的大小
file.setLength(fileSize);
file.close();
for (int i = 0; i < threadNum; i++) {
// //计算线程下载的开始位置和结束位置
int startIndex = i * currentPartSize;
int endIndex = (i + 1) *currentPartSize - 1;
if(i == threadNum - 1){
endIndex = fileSize - 1;
}
// 每个线程使用一个RandomAccessFile进行下载
RandomAccessFile currentPart = new RandomAccessFile(myfile, "rwd");
threads[i] = new DownThread(currentPart,startIndex, endIndex);
threads[i].start();
}
} } // 获取下载的完成百分比
public double getCompleteRate() {
// 统计多条线程已经下载的总大小
int sumSize = 0;
for (int i = 0; i < threadNum; i++) {
if(threads[i] == null)
sumSize += 0;
else
sumSize += threads[i].length;
}
// 返回已经完成的百分比
return sumSize * 1.0 / fileSize;
} private class DownThread extends Thread {
/**当前线程的下载位置**/
private int startPos;
/**当前线程下载的结束位置**/
private int endPos;
/**当前线程需要下载的文件块**/
private RandomAccessFile currentPart;
/**定义该线程已下载的字节数**/
public int length; public DownThread(RandomAccessFile currentPart, int startPos, int endPos) {
this.startPos = startPos;
this.currentPart = currentPart;
this.endPos = endPos;
} @Override
public void run() {
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url
.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept",
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, "
+ "application/x-shockwave-flash, application/xaml+xml, "
+ "application/vnd.ms-xpsdocument, application/x-ms-xbap, "
+ "application/x-ms-application, application/vnd.ms-excel, "
+ "application/vnd.ms-powerpoint, application/msword, */*");
conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
conn.connect();
if(conn.getResponseCode() == 206){
InputStream inStream = conn.getInputStream();
// 跳过startPos个字节,表明该线程只下载自己负责哪部分文件。
byte[] buffer = new byte[4*1024];
int hasRead;
currentPart.seek(startPos);
// 读取网络数据,并写入本地文件
while ((hasRead = inStream.read(buffer)) >0 ) {
currentPart.write(buffer, 0, hasRead);
// 累计该线程下载的总大小
length += hasRead;
}
Log.i(Thread.currentThread().getName(), String.valueOf(length));
currentPart.close();
inStream.close();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}

主代码

package xidian.dy.com.chujia;

import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast; import java.util.Timer;
import java.util.TimerTask; public class MainActivity extends AppCompatActivity {
EditText url;
EditText target;
Button downBn;
ProgressBar bar;
DownUtil downUtil;
private int mDownStatus; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // 获取程序界面中的三个界面控件
url = (EditText) findViewById(R.id.url);
target = (EditText) findViewById(R.id.target);
downBn = (Button) findViewById(R.id.download);
bar = (ProgressBar) findViewById(R.id.progressBar); // 创建一个Handler对象
final Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x123) {
bar.setProgress(mDownStatus);
}
}
}; downBn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
return;
// 初始化DownUtil对象(最后一个参数指定线程数)
downUtil = new DownUtil(url.getText().toString(),
target.getText().toString(), 4);
new Thread() {
@Override
public void run(){
try {
// 开始下载
downUtil.download();
}
catch (Exception e) {
e.printStackTrace();
}
// 定义每秒调度获取一次系统的完成进度
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// 获取下载任务的完成比率
double completeRate = downUtil.getCompleteRate();
mDownStatus = (int) (completeRate * 100);
// 发送消息通知界面更新进度条
Log.i(Thread.currentThread().getName(), String.valueOf(mDownStatus));
handler.sendEmptyMessage(0x123);
// 下载完全后取消任务调度
if (mDownStatus >= 100) {
showToastByRunnable(MainActivity.this, "下载完成", 2000);
timer.cancel();
}
}
}, 0, 100);
}
}.start();
}
});
}
/**
* 在非UI线程中使用Toast
* @param context 上下文
* @param text 用以显示的消息内容
* @param duration 消息显示的时间
* */
private void showToastByRunnable(final Context context, final CharSequence text, final int duration) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, text, duration).show();
}
});
}
}

权限控制

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xidian.dy.com.chujia">
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

Android多线程文件下载的更多相关文章

  1. Android多线程文件下载器

    本应用实现的是输入文件的网络的地址,点击button開始下载,下载过程中有进度条和后面的文本提示进度, 下载过程中button不可点击,防止反复的下载,完成下载后会进行Toast的提示显示, 而且回复 ...

  2. Android实现网络多线程文件下载

    实现原理 (1)首先获得下载文件的长度,然后设置本地文件的长度. (2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置. 如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M ...

  3. android 多线程

    本章讲述在android开发中,多线程的应用.多线程能够处理耗时的操作并优化程序的性能.本章主要介绍知识点,AsyncTask,Java线程池,ThreadPoolExecutor线程池类.本章案例只 ...

  4. 无废话Android之smartimageview使用、android多线程下载、显式意图激活另外一个activity,检查网络是否可用定位到网络的位置、隐式意图激活另外一个activity、隐式意图的配置,自定义隐式意图、在不同activity之间数据传递(5)

    1.smartimageview使用 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&q ...

  5. Andoid 更好的Android多线程下载框架

    概述 为什么是更好的Android多线程下载框架呢,原因你懂的,广告法嘛! 本篇我们我们就来聊聊多线程下载框架,先聊聊我们框架的特点: 多线程 多任务 断点续传 支持大文件 可以自定义下载数据库 高度 ...

  6. 更好的Android多线程下载框架

    /** * 作者:Pich * 原文链接:http://me.woblog.cn/ * QQ群:129961195 * Github:https://github.com/lifengsofts */ ...

  7. Android多线程分析之五:使用AsyncTask异步下载图像

    Android多线程分析之五:使用AsyncTask异步下载图像 罗朝辉 (http://www.cnblogs.com/kesalin) CC 许可,转载请注明出处 在本系列文章的第一篇<An ...

  8. Android多线程分析之四:MessageQueue的实现

    Android多线程分析之四:MessageQueue的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前面两篇文章<Androi ...

  9. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...

随机推荐

  1. 烂泥:学习mysql数据库主从同步复制原理

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 说明本篇文章部分转载自互联网. MySQL的Replication(英文为复制)是一个多MySQL数据库做主从同步的方案,特点是异步复制,广泛用在各种对 ...

  2. x01.Lab.StreetApp: MVVM

    Store App 特别适用于 MVVM 模式.由于要用到 SQLite,Bing Maps,所以第一步从网上搜索并安装这两个扩展.很难想象在智能手机上运行 SQL Server 这种巨无霸型数据库, ...

  3. TCL校园招聘——软件开发工程师(java) 只招5个。。。

    简介 TCL集团股份有限公司创立于1981年,是全球性规模经营的消费类电子企业集团之一,广州2010年亚运会合作伙伴,总部位于广东省惠州市仲恺高新区TCL科技大厦.旗下拥有TCL集团.TCL多媒体科技 ...

  4. cookie和session详解

    cookie和session的区别 二者的定义: 当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文字或是一些选择,都纪录下来.当下次你再光临同 ...

  5. speex进行音频去噪

    应用speex进行音频去噪,speex功能很强大,因为opus的出现,用speex进行编码/解码的人几乎没有了,但是用speex来进行降噪,去除回声,增益还是很多. 这里用speex进行音频去噪,主要 ...

  6. css多栏自适应布局

    css多栏自适应布局还是需要总结一下的,都是基本功. 一般使用position属性布局,或者用float属性布局,也可以使用display属性. 看资料说position适合首页布局,因为首页内容往往 ...

  7. 151003-动起来-Javascript

    Hi 玩了三天了,下午一会儿还有电影,心快收不回来了...不过,竟然无聊到想学习,你敢信? 下个规矩吧,以后每天早上起来在这里写东西,至少也得是个hi,或者以后都以这个为开头好了,算是个个人标志?申请 ...

  8. MMORGP大型游戏设计与开发(客户端架构 part13 of vegine)

    一些数据是需要不断改动的,程序不可能因为这些改动而不厌其烦的去改动代码,早期的这种做法就成了程序员们最悲哀的痛苦.自从有了数据管理后,程序的世界逐渐清晰,这些烦恼也不再出现,不过若是要很好的管理数据可 ...

  9. 【原创Android游戏】--猜数字游戏Version 0.1

    想当年高中时经常和小伙伴在纸上或者黑板上或者学习机上玩猜数字的游戏,在当年那个手机等娱乐设备在我们那还不是很普遍的时候是很好的一个消遣的游戏,去年的时候便写了一个Android版的猜数字游戏,只是当时 ...

  10. POJ 1696 Space Ant 【极角排序】

    题意:平面上有n个点,一只蚂蚁从最左下角的点出发,只能往逆时针方向走,走过的路线不能交叉,问最多能经过多少个点. 思路:每次都尽量往最外边走,每选取一个点后对剩余的点进行极角排序.(n个点必定能走完, ...