android多线程断点,android多线程断点下载——网络编

让我们看一下代码的实现方法。

packagecom.smart.db;

importjava.util.HashMap;

importjava.util.Map;

importandroid.content.Context;

importandroid.database.Cursor;

importandroid.database.sqlite.SQLiteDatabase;

/**

* 业务bean

*

*/

publicclassFileService {

privateDBOpenHelper openHelper;

publicFileService(Context context) {

openHelper = newDBOpenHelper(context);

}

/**

* 获取每条线程已经下载的文件长度

* @param path

* @return

*/

publicMap getData(String path){

SQLiteDatabase db = openHelper.getReadableDatabase();

Cursor cursor = db.rawQuery("select threadid, downlength from SmartFileDownlog where downpath=?",newString[]{path});

Map data = newHashMap();

while(cursor.moveToNext()){

data.put(cursor.getInt(0), cursor.getInt(1));

}

cursor.close();

db.close();

returndata;

}

/**

* 保存每条线程已经下载的文件长度

* @param path

* @param map

*/

publicvoidsave(String path,  Map map){//int threadid, int position

SQLiteDatabase db = openHelper.getWritableDatabase();

db.beginTransaction();

try{

for(Map.Entry entry : map.entrySet()){

db.execSQL("insert into SmartFileDownlog(downpath, threadid, downlength) values(?,?,?)",

newObject[]{path, entry.getKey(), entry.getValue()});

}

db.setTransactionSuccessful();

}finally{

db.endTransaction();

}

db.close();

}

/**

* 实时更新每条线程已经下载的文件长度

* @param path

* @param map

*/

publicvoidupdate(String path, Map map){

SQLiteDatabase db = openHelper.getWritableDatabase();

db.beginTransaction();

try{

for(Map.Entry entry : map.entrySet()){

db.execSQL("update SmartFileDownlog set downlength=? where downpath=? and threadid=?",

newObject[]{entry.getValue(), path, entry.getKey()});

}

db.setTransactionSuccessful();

}finally{

db.endTransaction();

}

db.close();

}

/**

* 当文件下载完成后,删除对应的下载记录

* @param path

*/

publicvoiddelete(String path){

SQLiteDatabase db = openHelper.getWritableDatabase();

db.execSQL("delete from SmartFileDownlog where downpath=?",newObject[]{path});

db.close();

}

}

packagecom.smart.impl;

importjava.io.File;

importjava.io.RandomAccessFile;

importjava.net.HttpURLConnection;

importjava.net.URL;

importjava.util.LinkedHashMap;

importjava.util.Map;

importjava.util.UUID;

importjava.util.concurrent.ConcurrentHashMap;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

importandroid.content.Context;

importandroid.util.Log;

importcom.smart.db.FileService;

/**

* 文件下载器

* @author lihuoming@sohu.com

*/

publicclassSmartFileDownloader {

privatestaticfinalString TAG ="SmartFileDownloader";

privateContext context;

privateFileService fileService;

/* 已下载文件长度 */

privateintdownloadSize =0;

/* 原始文件长度 */

privateintfileSize =0;

/* 线程数 */

privateSmartDownloadThread[] threads;

/* 本地保存文件 */

privateFile saveFile;

/* 缓存各线程下载的长度*/

privateMap data =newConcurrentHashMap();

/* 每条线程下载的长度 */

privateintblock;

/* 下载路径  */

privateString downloadUrl;

/**

* 获取线程数

*/

publicintgetThreadSize() {

returnthreads.length;

}

/**

* 获取文件大小

* @return

*/

publicintgetFileSize() {

returnfileSize;

}

/**

* 累计已下载大小

* @param size

*/

protectedsynchronizedvoidappend(intsize) {

downloadSize += size;

}

/**

* 更新指定线程最后下载的位置

* @param threadId 线程id

* @param pos 最后下载的位置

*/

protectedvoidupdate(intthreadId,intpos) {

this.data.put(threadId, pos);

}

/**

* 保存记录文件

*/

protectedsynchronizedvoidsaveLogFile() {

this.fileService.update(this.downloadUrl,this.data);

}

/**

* 构建文件下载器

* @param downloadUrl 下载路径

* @param fileSaveDir 文件保存目录

* @param threadNum 下载线程数

*/

publicSmartFileDownloader(Context context, String downloadUrl, File fileSaveDir,intthreadNum) {

try{

this.context = context;

this.downloadUrl = downloadUrl;

fileService = newFileService(this.context);

URL url = newURL(this.downloadUrl);

if(!fileSaveDir.exists()) fileSaveDir.mkdirs();

this.threads =newSmartDownloadThread[threadNum];

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setConnectTimeout(5*1000);

conn.setRequestMethod("GET");

conn.setRequestProperty("Accept","p_w_picpath/gif, p_w_picpath/jpeg, p_w_picpath/pjpeg, p_w_picpath/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("Referer", downloadUrl);

conn.setRequestProperty("Charset","UTF-8");

conn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");

conn.setRequestProperty("Connection","Keep-Alive");

conn.connect();

printResponseHeader(conn);

if(conn.getResponseCode()==200) {

this.fileSize = conn.getContentLength();//根据响应获取文件大小

if(this.fileSize <=0)thrownewRuntimeException("Unkown file size ");

String filename = getFileName(conn);

this.saveFile =newFile(fileSaveDir, filename);/* 保存文件 */

Map logdata = fileService.getData(downloadUrl);

if(logdata.size()>0){

for(Map.Entry entry : logdata.entrySet())

data.put(entry.getKey(), entry.getValue());

}

this.block = (this.fileSize %this.threads.length)==0?this.fileSize /this.threads.length :this.fileSize /this.threads.length +1;

if(this.data.size()==this.threads.length){

for(inti =0; i 

this.downloadSize +=this.data.get(i+1);

}

print("已经下载的长度"+this.downloadSize);

}

}else{

thrownewRuntimeException("server no response ");

}

} catch(Exception e) {

print(e.toString());

thrownewRuntimeException("don't connection this url");

}

}

/**

* 获取文件名

*/

privateString getFileName(HttpURLConnection conn) {

String filename = this.downloadUrl.substring(this.downloadUrl.lastIndexOf('/') +1);

if(filename==null||"".equals(filename.trim())){//如果获取不到文件名称

for(inti =0;; i++) {

String mine = conn.getHeaderField(i);

if(mine ==null)break;

if("content-disposition".equals(conn.getHeaderFieldKey(i).toLowerCase())){

Matcher m = Pattern.compile(".*filename=(.*)").matcher(mine.toLowerCase());

if(m.find())returnm.group(1);

}

}

filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名

}

returnfilename;

}

/**

*  开始下载文件

* @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null

* @return 已下载文件大小

* @throws Exception

*/

publicintdownload(SmartDownloadProgressListener listener)throwsException{

try{

RandomAccessFile randOut = newRandomAccessFile(this.saveFile,"rw");

if(this.fileSize>0) randOut.setLength(this.fileSize);

randOut.close();

URL url = newURL(this.downloadUrl);

if(this.data.size() !=this.threads.length){

this.data.clear();//清除数据

for(inti =0; i 

this.data.put(i+1,0);

}

}

for(inti =0; i 

intdownLength =this.data.get(i+1);

if(downLength 

this.threads =newSmartDownloadThread(this, url,this.saveFile,this.block,this.data.get(i+1), i+1);

this.threads.setPriority(7);

this.threads.start();

}else{

this.threads =null;

}

}

this.fileService.save(this.downloadUrl,this.data);

booleannotFinish =true;//下载未完成

while(notFinish) {// 循环判断是否下载完毕

Thread.sleep(900);

notFinish = false;//假定下载完成

for(inti =0; i 

if(this.threads !=null&& !this.threads.isFinish()) {

notFinish = true;//下载没有完成

if(this.threads.getDownLength() == -1){//如果下载失败,再重新下载

this.threads =newSmartDownloadThread(this, url,this.saveFile,this.block,this.data.get(i+1), i+1);

this.threads.setPriority(7);

this.threads.start();

}

}

}

if(listener!=null) listener.onDownloadSize(this.downloadSize);

}

fileService.delete(this.downloadUrl);

} catch(Exception e) {

print(e.toString());

thrownewException("file download fail");

}

returnthis.downloadSize;

}

/**

* 获取Http响应头字段

* @param http

* @return

*/

publicstaticMap getHttpResponseHeader(HttpURLConnection http) {

Map header = newLinkedHashMap();

for(inti =0;; i++) {

String mine = http.getHeaderField(i);

if(mine ==null)break;

header.put(http.getHeaderFieldKey(i), mine);

}

returnheader;

}

/**

* 打印Http头字段

* @param http

*/

publicstaticvoidprintResponseHeader(HttpURLConnection http){

Map header = getHttpResponseHeader(http);

for(Map.Entry entry : header.entrySet()){

String key = entry.getKey()!=null? entry.getKey()+":":"";

print(key+ entry.getValue());

}

}

//打印日志

privatestaticvoidprint(String msg){

Log.i(TAG, msg);

}

}

packagecom.smart.impl;

importjava.io.File;

importjava.io.InputStream;

importjava.io.RandomAccessFile;

importjava.net.HttpURLConnection;

importjava.net.URL;

importandroid.util.Log;

publicclassSmartDownloadThreadextendsThread {

privatestaticfinalString TAG ="SmartDownloadThread";

privateFile saveFile;

privateURL downUrl;

privateintblock;

/* *下载开始位置  */

privateintthreadId = -1;

privateintdownLength;

privatebooleanfinish =false;

privateSmartFileDownloader downloader;

publicSmartDownloadThread(SmartFileDownloader downloader, URL downUrl, File saveFile,intblock,intdownLength,intthreadId) {

this.downUrl = downUrl;

this.saveFile = saveFile;

this.block = block;

this.downloader = downloader;

this.threadId = threadId;

this.downLength = downLength;

}

@Override

publicvoidrun() {

if(downLength 

try{

HttpURLConnection http = (HttpURLConnection) downUrl.openConnection();

http.setConnectTimeout(5*1000);

http.setRequestMethod("GET");

http.setRequestProperty("Accept","p_w_picpath/gif, p_w_picpath/jpeg, p_w_picpath/pjpeg, p_w_picpath/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, */*");

http.setRequestProperty("Accept-Language","zh-CN");

http.setRequestProperty("Referer", downUrl.toString());

http.setRequestProperty("Charset","UTF-8");

intstartPos = block * (threadId -1) + downLength;//开始位置

intendPos = block * threadId -1;//结束位置

http.setRequestProperty("Range","bytes="+ startPos +"-"+ endPos);//设置获取实体数据的范围

http.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");

http.setRequestProperty("Connection","Keep-Alive");

InputStream inStream = http.getInputStream();

byte[] buffer =newbyte[1024];

intoffset =0;

print("Thread "+this.threadId +" start download from position "+ startPos);

RandomAccessFile threadfile = newRandomAccessFile(this.saveFile,"rwd");

threadfile.seek(startPos);

while((offset = inStream.read(buffer,0,1024)) != -1) {

threadfile.write(buffer, 0, offset);

downLength += offset;

downloader.update(this.threadId, downLength);

downloader.saveLogFile();

downloader.append(offset);

}

threadfile.close();

inStream.close();

print("Thread "+this.threadId +" download finish");

this.finish =true;

} catch(Exception e) {

this.downLength = -1;

print("Thread "+this.threadId+":"+ e);

}

}

}

privatestaticvoidprint(String msg){

Log.i(TAG, msg);

}

/**

* 下载是否完成

* @return

*/

publicbooleanisFinish() {

returnfinish;

}

/**

* 已经下载的内容大小

* @return 如果返回值为-1,代表下载失败

*/

publiclonggetDownLength() {

returndownLength;

}

}

packagecom.smart.activoty.download;

importjava.io.File;

importandroid.app.Activity;

importandroid.os.Bundle;

importandroid.os.Environment;

importandroid.os.Handler;

importandroid.os.Message;

importandroid.view.View;

importandroid.widget.Button;

importandroid.widget.EditText;

importandroid.widget.ProgressBar;

importandroid.widget.TextView;

importandroid.widget.Toast;

importcom.smart.impl.SmartDownloadProgressListener;

importcom.smart.impl.SmartFileDownloader;

publicclassSmartDownloadActivityextendsActivity {

privateProgressBar downloadbar;

privateEditText pathText;

privateTextView resultView;

privateHandler handler =newHandler(){

@Override//信息

publicvoidhandleMessage(Message msg) {

switch(msg.what) {

case1:

intsize = msg.getData().getInt("size");

downloadbar.setProgress(size);

floatresult = (float)downloadbar.getProgress()/ (float)downloadbar.getMax();

intp = (int)(result*100);

resultView.setText(p+"%");

if(downloadbar.getProgress()==downloadbar.getMax())

Toast.makeText(SmartDownloadActivity.this, R.string.success,1).show();

break;

case-1:

Toast.makeText(SmartDownloadActivity.this, R.string.error,1).show();

break;

}

}

};

@Override

publicvoidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

Button button = (Button)this.findViewById(R.id.button);

downloadbar = (ProgressBar)this.findViewById(R.id.downloadbar);

pathText = (EditText)this.findViewById(R.id.path);

resultView = (TextView)this.findViewById(R.id.result);

button.setOnClickListener(newView.OnClickListener() {

@Override

publicvoidonClick(View v) {

String path = pathText.getText().toString();

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){

File dir = Environment.getExternalStorageDirectory();//文件保存目录

download(path, dir);

}else{

Toast.makeText(SmartDownloadActivity.this, R.string.sdcarderror,1).show();

}

}

});

}

//对于UI控件的更新只能由主线程(UI线程)负责,如果在非UI线程更新UI控件,更新的结果不会反映在屏幕上,某些控件还会出错

privatevoiddownload(finalString path,finalFile dir){

newThread(newRunnable() {

@Override

publicvoidrun() {

try{

SmartFileDownloader loader = newSmartFileDownloader(SmartDownloadActivity.this, path, dir,3);

intlength = loader.getFileSize();//获取文件的长度

downloadbar.setMax(length);

loader.download(newSmartDownloadProgressListener(){

@Override

publicvoidonDownloadSize(intsize) {//可以实时得到文件下载的长度

Message msg = newMessage();

msg.what = 1;

msg.getData().putInt("size", size);

handler.sendMessage(msg);

}});

} catch(Exception e) {

Message msg = newMessage();//信息提示

msg.what = -1;

msg.getData().putString("error","下载失败");//如果下载错误,显示提示失败!

handler.sendMessage(msg);

}

}

}).start();//开始

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值