XUtils
下面给大家介绍android的一个开源项目,它可以帮你干好多事情,废话不多说,步入正题:
这是xUtil的下载地址,在GitHub
目前xUtils主要的四大模块:
DbUtils模块:
android中的orm框架,一行代码就可以进行增删改查;
支持事务,默认关闭;
可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);
支持绑定外键,保存实体时外键关联实体自动保存或更新;
自动加载外键关联实体,支持延时加载;
支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。
ViewUtils模块:
android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;
新的事件绑定方式,使用混淆工具混淆后仍可正常工作;
目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。
HttpUtils模块:
支持同步,异步方式的请求;
支持大文件上传,上传大文件不会oom;
支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;
下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;
返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。
BitmapUtils模块:
加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;
支持加载网络图片和本地图片;
内存管理使用lru算法,更好的管理bitmap内存;
可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等...
接下来,先给大家讲解一下多线程下载的原理:
如何实现多线程:
1 如何等分服务器资源 (RandomAccessFile)
2 如何在客户端创建一个大小和服务器一模一样的文件
3 如何开启多个线程
4 如何知道每个线程都下载完毕
path = “http://localhost:9019/01.exe“; 这个网址是我tomcat的服务器,你可以在tomcat的apache-tomcat-7.0.42\webapps\ROOT 文件夹下放一个exe文件,下载它,运行tomcat服务器,localhost是你电脑的IP地址。
下面我用java写一下多线程的原理:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class MutilDownload {
private static String path = "http://localhost:9019/01.exe";
private static int threadCount = 3;//线程的数量
private static int runningThread;//当前正在运行的线程
/**
* @param args
*/
@SuppressWarnings("resource")
public static void main(String[] args) {
// 获取到服务器的资源
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
int code = conn.getResponseCode();
if (code == 200) {
// 1 获取服务器资源的大小
int length = conn.getContentLength();
System.out.println("length:" + length);
runningThread = threadCount;//当前正在运行的线程数
// 2 要知道如何从客户端创建一个大小和服务器一模一样的文件
RandomAccessFile raf = new RandomAccessFile(getFileName(path), "rw");
raf.setLength(length);//设置和服务器大小一样的文件
// 3 如何等分服务器的资源 length
int threadBiockSize = length / threadCount;// 每个线程下载的大小
for (int i = 0; i < threadCount; i++) {
int startIndex = i * threadBiockSize;// 每个线程下载开始的位置
int endIndex = (i + 1) * threadBiockSize - 1;// 每个线程下载的结束位置
// 最后一个线程
if (i == threadCount - 1) {
endIndex = length - 1;
}
System.out.println("线程id:"+i+"理论的下载位置--:"+startIndex+"-----"+endIndex);
// 开启多个线程去下载
new DownloadThread(path, startIndex, endIndex, i).start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 开启多个线程下载
* @author Blake
*
*/
private static class DownloadThread extends Thread {
private String path;
private int startIndex;
private int endIndex;
private int threadId;
@SuppressWarnings("unused")
public DownloadThread(String path, int startIndex, int endIndex,
int threadId) {
this.path = path;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@SuppressWarnings("resource")
@Override
public void run() {
// 下载
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
// 断点续传 判断是否有下载的记录
File file = new File(threadId + ".txt");
if (file.exists() && file.length() > 0) {
// 读取上次保存的位置
FileInputStream fis = new FileInputStream(file);
BufferedReader bfr = new BufferedReader(
new InputStreamReader(fis));
String lastPositin = bfr.readLine();// 上一次下载的位置
// 按照上次的位置继续下载
conn.setRequestProperty("Range", "bytes=" + lastPositin+ "-" + endIndex);
//要改变一下statindex 的位置
startIndex = Integer.parseInt(lastPositin);
System.out.println("线程id:"+threadId+"真实的下载位置--:"+startIndex+"-----"+endIndex);
fis.close();
} else {
// 因为开启多个线程去下载,要设置一个头信息,告诉服务器每个线程每个线程下载的位置
conn.setRequestProperty("Range", "bytes=" + startIndex
+ "-" + endIndex);
}
int code = conn.getResponseCode();
if (code == 206) {// 返回服务器部分资源
InputStream in = conn.getInputStream();
// 把数据写到文件中
RandomAccessFile raf = new RandomAccessFile(getFileName(path),"rw");
raf.seek(startIndex);
// 做断点续传 就是我把每个多线程下载的位置记录起来
int len = -1;
int total = 0;
byte buffer[] = new byte[1024*1024];
while ((len = in.read(buffer)) != -1) {
raf.write(buffer, 0, len);
// 记录当前线程下载的位置
total += len;// 当前线程下载的大小
int currentThreadPosition = startIndex + total;// 当前线程下载的位置
// 把这个位置记录下来
RandomAccessFile rAccessFile = new RandomAccessFile(
threadId + ".txt", "rwd");// 把数据同步到低层设备
rAccessFile.write(String.valueOf(currentThreadPosition)
.getBytes());
rAccessFile.close();
}
raf.close();
in.close();
System.out.println("线程-----下载完毕" + threadId);
//开一个锁
synchronized (DownloadThread.class) {
runningThread--;
if (runningThread <=0) {
//说明所有的线程都下载完毕 我把.txt文件删除
for (int i = 0; i < threadCount; i++) {
File deleteFile = new File(i+".txt");
deleteFile.delete();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
super.run();
}
}
/**
* 截取下载的路径
* @param path
* @return
*/
public static String getFileName(String path){
int start=path.lastIndexOf("/")+1;
return path.substring(start);
}
}
这是多线程下载的核心代码,看到这么多代码是不是很麻烦!!!!
接下我们用开源的项目来做就很简单了
1 首先把开源的com包导入项目中
HttpUtils http = new HttpUtils();
/**
* url 下载的路径
* target 下载文件保存的路径
* autoResume 是否支持断点续传
*/
http.download("http://localhost:9019/01.exe", "/mnt/sdcard/haha.exe", true,new RequestCallBack<File>() {
@Override
public void onSuccess(ResponseInfo<File> responseInfo) {
Toast.makeText(getApplicationContext(), responseInfo.result.getPath(), 1).show();
}
@Override
public void onFailure(HttpException error, String msg) {
}
/**
* 加载进度 pb为进度条,实现进度条进度加载
* total 总得大小
* current 当前的大小
*/
@Override
public void onLoading(long total, long current, boolean isUploading) {
pb.setMax((int) total);
pb.setProgress((int) current);
}
});
怎么样就这么几行代码,便实现了多线程断点续传下载和进度条加载进度。
还有更多的功能自己去探索吧!