Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 789|回复: 0

开发交流:Android 多任务多线程断点下载

[复制链接]

该用户从未签到

发表于 2011-10-24 10:49:45 | 显示全部楼层 |阅读模式
让我们看一下代码的实现方法。 package com.smart.db;   

import java.util.HashMap;   

import java.util.Map;   

import android.content.Context;   

import android.database.Cursor;   

import android.database.sqlite.SQLiteDatabase;   

/**   

* 业务bean   

*   

*/   

public class FileService {   

private DBOpenHelper openHelper;   

public FileService(Context context) {   

  openHelper = new DBOpenHelper(context);   

}   

/**   

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

  * @param path   

  * @return   

  */   

public Map<Integer, Integer> getData(String path){   

  SQLiteDatabase db = openHelper.getReadableDatabase();   

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

  Map<Integer, Integer> data = new HashMap<Integer, Integer>();   

  while(cursor.moveToNext()){   

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

  }   

  cursor.close();   

  db.close();   

  return data;   

}   

/**   

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

  * @param path   

  * @param map   

  */   

public void save(String path,  Map<Integer, Integer> map){//int threadid, int position   

  SQLiteDatabase db = openHelper.getWritableDatabase();   

  db.beginTransaction();   

  try{   

   for(Map.Entry<Integer, Integer> entry : map.entrySet()){   

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

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

   }   

   db.setTransactionSuccessful();   

  }finally{   

   db.endTransaction();   

  }   

  db.close();   

}   

/**   

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

  * @param path   

  * @param map   

  */   

public void update(String path, Map<Integer, Integer> map){   

  SQLiteDatabase db = openHelper.getWritableDatabase();   

  db.beginTransaction();   

  try{   

   for(Map.Entry<Integer, Integer> entry : map.entrySet()){   

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

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

   }   

   db.setTransactionSuccessful();   

  }finally{   

   db.endTransaction();   

  }   

  db.close();   

}   

/**   

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

  * @param path   

  */   

public void delete(String path){   

  SQLiteDatabase db = openHelper.getWritableDatabase();   

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

  db.close();   

}   

   

}   

package com.smart.impl;   

import java.io.File;   

import java.io.RandomAccessFile;   

import java.net.HttpURLConnection;   

import java.net.URL;   

import java.util.LinkedHashMap;   

import java.util.Map;   

import java.util.UUID;   

import java.util.concurrent.ConcurrentHashMap;   

import java.util.regex.Matcher;   

import java.util.regex.Pattern;   

import android.content.Context;   

import android.util.Log;   

import com.smart.db.FileService;   

/**   

* 文件下载器   

* @author lihuoming@sohu.com   

*/   

public class SmartFileDownloader {   

private static final String TAG = "SmartFileDownloader";   

private Context context;   

private FileService fileService;   

/* 已下载文件长度 */   

private int downloadSize = 0;   

/* 原始文件长度 */   

private int fileSize = 0;   

/* 线程数 */   

private SmartDownloadThread[] threads;   

/* 本地保存文件 */   

private File saveFile;   

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

private Map<Integer, Integer> data = new ConcurrentHashMap<Integer, Integer>();   

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

private int block;   

/* 下载路径  */   

private String downloadUrl;   

/**   

  * 获取线程数   

  */   

public int getThreadSize() {   

  return threads.length;   

}   

/**   

  * 获取文件大小   

  * @return   

  */   

public int getFileSize() {   

  return fileSize;   

}   

/**   

  * 累计已下载大小   

  * @param size   

  */   

protected synchronized void append(int size) {   

  downloadSize += size;   

}   

/**   

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

  * @param threadId 线程id   

  * @param pos 最后下载的位置   

  */   

protected void update(int threadId, int pos) {   

  this.data.put(threadId, pos);   

}   

/**   

  * 保存记录文件   

  */   

protected synchronized void saveLogFile() {   

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

}   

/**   

  * 构建文件下载器   

  * @param downloadUrl 下载路径   

  * @param fileSaveDir 文件保存目录   

  * @param threadNum 下载线程数   

  */   

public SmartFileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum) {   

  try {   

   this.context = context;   

   this.downloadUrl = downloadUrl;   

   fileService = new FileService(this.context);   

   URL url = new URL(this.downloadUrl);   

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

   this.threads = new SmartDownloadThread[threadNum];        

   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("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) throw new RuntimeException("Unkown file size ");         

    String filename = getFileName(conn);   

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

    Map<Integer, Integer> logdata = fileService.getData(downloadUrl);   

    if(logdata.size()>0){   

     for(Map.Entry<Integer, Integer> 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 (int i = 0; i < this.threads.length; i++) {   

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

     }   

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

    }      

   }else{   

    throw new RuntimeException("server no response ");   

   }   

  } catch (Exception e) {   

   print(e.toString());   

   throw new RuntimeException("don't connection this url");   

  }   

}   

/**   

  * 获取文件名   

  */   

private String getFileName(HttpURLConnection conn) {   

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

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

   for (int i = 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()) return m.group(1);   

    }   

   }   

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

  }   

  return filename;   

}   

/**   

  *  开始下载文件   

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

  * @return 已下载文件大小   

  * @throws Exception   

  */   

public int download(SmartDownloadProgressListener listener) throws Exception{   

  try {   

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

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

   randOut.close();   

   URL url = new URL(this.downloadUrl);   

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

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

    for (int i = 0; i < this.threads.length; i++) {   

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

    }   

   }   

   for (int i = 0; i < this.threads.length; i++) {   

    int downLength = this.data.get(i+1);   

    if(downLength < this.block && this.downloadSize<this.fileSize){ //该线程未完成下载时,继续下载         

     this.threads = new SmartDownloadThread(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);   

   boolean notFinish = true;//下载未完成   

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

    Thread.sleep(900);   

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

    for (int i = 0; i < this.threads.length; i++){   

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

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

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

       this.threads = new SmartDownloadThread(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());   

   throw new Exception("file download fail");   

  }   

  return this.downloadSize;   

}   

/**   

  * 获取Http响应头字段   

  * @param http   

  * @return   

  */   

public static Map<String, String> getHttpResponseHeader(HttpURLConnection http) {   

  Map<String, String> header = new LinkedHashMap<String, String>();   

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

   String mine = http.getHeaderField(i);   

   if (mine == null) break;   

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

  }   

  return header;   

}   

/**   

  * 打印Http头字段   

  * @param http   

  */   

public static void printResponseHeader(HttpURLConnection http){   

  Map<String, String> header = getHttpResponseHeader(http);   

  for(Map.Entry<String, String> entry : header.entrySet()){   

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

   print(key+ entry.getValue());   

  }   

}   

//打印日志   

private static void print(String msg){   

  Log.i(TAG, msg);   

}   

}   

package com.smart.impl;   

import java.io.File;   

import java.io.InputStream;   

import java.io.RandomAccessFile;   

import java.net.HttpURLConnection;   

import java.net.URL;   

import android.util.Log;   

public class SmartDownloadThread extends Thread {   

private static final String TAG = "SmartDownloadThread";   

private File saveFile;   

private URL downUrl;   

private int block;   

/* *下载开始位置  */   

private int threadId = -1;   

private int downLength;   

private boolean finish = false;   

private SmartFileDownloader downloader;   

public SmartDownloadThread(SmartFileDownloader downloader, URL downUrl, File saveFile, int block, int downLength, int threadId) {   

  this.downUrl = downUrl;   

  this.saveFile = saveFile;   

  this.block = block;   

  this.downloader = downloader;   

  this.threadId = threadId;   

  this.downLength = downLength;   

}   

@Override   

public void run() {   

  if(downLength < block){//未下载完成   

   try {   

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

    http.setConnectTimeout(5 * 1000);   

    http.setRequestMethod("GET");   

    http.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, */*");   

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

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

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

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

    int endPos = 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 = new byte[1024];   

    int offset = 0;   

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

    RandomAccessFile threadfile = new RandomAccessFile(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);   

   }   

  }   

}   

private static void print(String msg){   

  Log.i(TAG, msg);   

}   

/**   

  * 下载是否完成   

  * @return   

  */   

public boolean isFinish() {   

  return finish;   

}   

/**   

  * 已经下载的内容大小   

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

  */   

public long getDownLength() {   

  return downLength;   

}   

}   

package com.smart.activoty.download;   

import java.io.File;   

import android.app.Activity;   

import android.os.Bundle;   

import android.os.Environment;   

import android.os.Handler;   

import android.os.Message;   

import android.view.View;   

import android.widget.Button;   

import android.widget.EditText;   

import android.widget.ProgressBar;   

import android.widget.TextView;   

import android.widget.Toast;   

import com.smart.impl.SmartDownloadProgressListener;   

import com.smart.impl.SmartFileDownloader;   

public class SmartDownloadActivity extends Activity {   

    private ProgressBar downloadbar;   

    private EditText pathText;   

    private TextView resultView;   

    private Handler handler = new Handler(){   

  @Override//信息   

  public void handleMessage(Message msg) {   

   switch (msg.what) {   

   case 1:   

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

    downloadbar.setProgress(size);   

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

    int p = (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   

    public void onCreate(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(new View.OnClickListener() {      

   @Override   

   public void onClick(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控件,更新的结果不会反映在屏幕上,某些控件还会出错   

    private void download(final String path, final File dir){   

     new Thread(new Runnable() {   

   @Override   

   public void run() {   

    try {   

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

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

     downloadbar.setMax(length);   

     loader.download(new SmartDownloadProgressListener(){   

      @Override   

      public void onDownloadSize(int size) {//可以实时得到文件下载的长度   

       Message msg = new Message();   

       msg.what = 1;   

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

       handler.sendMessage(msg);   

      }});   

    } catch (Exception e) {   

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

     msg.what = -1;   

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

     handler.sendMessage(msg);   

    }   

   }   

  }).start();//开始         

    }   

}   
复制代码
回复

使用道具 举报

头像被屏蔽

该用户从未签到

发表于 2012-5-8 11:26:27 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-12 03:05 , Processed in 0.308768 second(s), 36 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表