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);
}
});
怎麼樣就這麼幾行代碼,便實現了多線程斷點續傳下載和進度條加載進度。
還有更多的功能自己去探索吧!