package com.young.download.factory; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.net.URL; import java.net.URLConnection; import android.util.Log; /** * * 文件下载类 * */ public class FileDownloadThread extends Thread { private static final String TAG = "FileDownloadThread"; /** 缓冲区 */ private static final int BUFF_SIZE = 1024; /** 需要下载的URL */ private URL url; /** 缓存的FIle */ private File file; /** 开始位置 */ private int startPosition; /** 结束位置 */ private int endPosition; /** 当前位置 */ private int curPosition; /** 完成 */ private boolean finished = false; /** 已经下载多少 */ private int downloadSize = 0; /*** * 分块文件下载,可以创建多线程模式 * * @param url * 下载的URL * @param file * 下载的文件 * @param startPosition * 开始位置 * @param endPosition * 结束位置 */ public FileDownloadThread(URL url, File file, int startPosition, int endPosition) { this.url = url; this.file = file; this.startPosition = startPosition; this.curPosition = startPosition; this.endPosition = endPosition; Log.e(TAG, toString()); } @Override public void run() { BufferedInputStream bis = null; RandomAccessFile rAccessFile = null; byte[] buf = new byte[BUFF_SIZE]; URLConnection conn = null; try { conn = url.openConnection(); conn.setConnectTimeout(10000);// 设置超时 conn.setReadTimeout(10000); conn.setAllowUserInteraction(true); System.out.println(this.getName() + " startPosition " + startPosition + " endPosition " + endPosition); // 根据范围下载数据 conn.setRequestProperty("Range", "bytes=" + (startPosition) + "-" + endPosition); // 读写 rAccessFile = new RandomAccessFile(file, "rwd"); // 从某个地方开始写入数据 rAccessFile.seek(startPosition); bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE); // 当前位置小于结束位置 继续下载 while (curPosition < endPosition) { int len = bis.read(buf, 0, BUFF_SIZE); // 下载完成 if (len == -1) { break; } rAccessFile.write(buf, 0, len); curPosition = curPosition + len; // 如果下载多了,则减去多余部分 if (curPosition > endPosition) { System.out.println(" curPosition > endPosition !!!!"); int extraLen = curPosition - endPosition; downloadSize += (len - extraLen + 1); } else { downloadSize += len; } } this.finished = true; // 当前阶段下载完成 Log.e(TAG, "当前" + this.getName() + "下载完成"); } catch (Exception e) { Log.e(TAG, "download error Exception " + e.getMessage()); e.printStackTrace(); } finally { try { // 关闭流 bis.close(); rAccessFile.close(); } catch (IOException e) { Log.e("AccessFile", "AccessFile IOException " + e.getMessage()); } } super.run(); } /** * 是否完成当前段下载完成 * * @return */ public boolean isFinished() { return finished; } /** * 已经下载多少 * * @return */ public int getDownloadSize() { return downloadSize; } @Override public String toString() { return "FileDownloadThread [url=" + url + ", file=" + file + ", startPosition=" + startPosition + ", endPosition=" + endPosition + ", curPosition=" + curPosition + ", finished=" + finished + ", downloadSize=" + downloadSize + "]"; } }
2.更新信息处理类
package com.young.download.factory; import java.io.File; import java.io.RandomAccessFile; import java.net.URL; import java.net.URLConnection; import android.os.Handler; import android.os.Message; import android.util.Log; import com.young.download.util.FileUtil; /** * 多线程下载,UI更新类 * **/ public class MultiThreadDownload extends Thread { private static final String TAG = "MultiThreadDownload"; /** 每一个线程需要下载的大小 */ private int blockSize; /*** * 线程数量<br> * 默认为5个线程下载 */ private int threadNum = 2; /*** 文件大小 */ private int fileSize; /** * 已经下载多少 */ private int downloadSize; /** 文件的url,线程编号,文件名称 */ private String UrlStr, ThreadNo, fileName; /*** 保存的路径 */ private String savePath; /** 下载的百分比 */ private int downloadPercent = 0; /** 下载的 平均速度 */ private int downloadSpeed = 0; /** 下载用的时间 */ private int usedTime = 0; /** 当前时间 */ private long curTime; /** 是否已经下载完成 */ private boolean completed = false; private Handler handler; /** * 下载的构造函数 * * @param url * 请求下载的URL * @param handler * UI更新使用 * @param savePath * 保存文件的路径 */ public MultiThreadDownload(Handler handler, String url, String savePath) { this.handler = handler; this.UrlStr = url; this.savePath = savePath; Log.e(TAG, toString()); } @Override public void run() { FileDownloadThread[] fds = new FileDownloadThread[threadNum];// 设置线程数量 try { URL url = new URL(UrlStr); URLConnection conn = url.openConnection(); fileSize = conn.getContentLength(); this.fileName = FileUtil.getFileName(UrlStr); // 只创建一个文件,saveFile下载内容 File saveFile = new File(savePath + "/" + fileName); Log.e(TAG, "文件一共:" + fileSize + " savePath " + savePath + " fileName " + fileName); // 下载的文件内容 RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rwd"); // 设置本地文件的长度和下载文件相同 accessFile.setLength(fileSize); accessFile.close(); // Handler更新UI,发送消息 sendMsg(FileUtil.startDownloadMeg); // 每个线程下载的数据量 blockSize = ((fileSize % threadNum) == 0) ? (fileSize / threadNum) : (fileSize / threadNum + 1); Log.e(TAG, "每个线程分别下载 :" + blockSize); for (int i = 0; i < threadNum; i++) { int curThreadEndPosition = (i + 1) != threadNum ? ((i + 1) * blockSize - 1) : fileSize; FileDownloadThread fdt = new FileDownloadThread(url, saveFile, i * blockSize, curThreadEndPosition); fdt.setName("thread" + i); fdt.start(); fds[i] = fdt; } /** * 获取数据,更新UI,直到所有下载线程都下载完成。 */ boolean finished = false; // 开始时间,放在循环外,求解的usedTime就是总时间 long startTime = System.currentTimeMillis(); while (!finished) { downloadSize = 0; finished = true; for (int i = 0; i < fds.length; i++) { downloadSize += fds[i].getDownloadSize(); if (!fds[i].isFinished()) { finished = false; } } downloadPercent = (downloadSize * 100) / fileSize; curTime = System.currentTimeMillis(); System.out.println("curTime = " + curTime + " downloadSize = " + downloadSize + " usedTime " + (int) ((curTime - startTime) / 1000)); usedTime = (int) ((curTime - startTime) / 1000); if (usedTime == 0) usedTime = 1; downloadSpeed = (downloadSize / usedTime) / 1024; sleep(1000);/* 1秒钟刷新一次界面 */ sendMsg(FileUtil.updateDownloadMeg); } Log.e(TAG, "下载完成"); completed = true; sendMsg(FileUtil.endDownloadMeg); } catch (Exception e) { Log.e(TAG, "multi file error Exception " + e.getMessage()); e.printStackTrace(); } super.run(); } /** * 得到文件的大小 * * @return */ public int getFileSize() { return this.fileSize; } /** * 得到已经下载的数量 * * @return */ public int getDownloadSize() { return this.downloadSize; } /** * 获取下载百分比 * * @return */ public int getDownloadPercent() { return this.downloadPercent; } /** * 获取下载速度 * * @return */ public int getDownloadSpeed() { return this.downloadSpeed; } /** * 修改默认线程数 * * @param threadNum */ public void setThreadNum(int threadNum) { this.threadNum = threadNum; } /** * 分块下载完成的标志 * * @return */ public boolean isCompleted() { return this.completed; } @Override public String toString() { return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize=" + fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo + ", savePath=" + savePath + "]"; } /** * 发送消息,用户提示 * */ private void sendMsg(int what) { Message msg = new Message(); msg.what = what; handler.sendMessage(msg); } }
3.Activity类
package com.young.download; import java.io.File; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.Toast; import com.young.download.factory.MultiThreadDownload; import com.young.download.util.FileUtil; public class MainActivity extends Activity implements OnClickListener { protected static final String TAG = "MainActivity"; private Button button; private ProgressBar pb; // 需要下载的文件 private String url = "http://gdown.baidu.com/data/wisegame/3c00add7144d3915/kugouyinle.apk"; private MultiThreadDownload mUpdateUIThread = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); button = (Button) this.findViewById(R.id.button); button.setOnClickListener(this); pb = (ProgressBar) this.findViewById(R.id.pb); mUpdateUIThread = new MultiThreadDownload(handler, url, FileUtil.setMkdir(this) + File.separator); } @Override public void onClick(View v) { mUpdateUIThread.start(); } // 对返回的数据进行处理 private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case FileUtil.startDownloadMeg: // 设置进度条中最大的值是文件的大小 pb.setMax(mUpdateUIThread.getFileSize()); break; case FileUtil.updateDownloadMeg: if (!mUpdateUIThread.isCompleted()) // 下载 { Log.e(TAG, "已下载:" + mUpdateUIThread.getDownloadSize()); pb.setProgress(mUpdateUIThread.getDownloadSize()); button.setText("下载速度:" + mUpdateUIThread.getDownloadSpeed() + "k/秒 下载百分比" + mUpdateUIThread.getDownloadPercent() + "%"); } else { button.setText("下载完成"); } break; case FileUtil.endDownloadMeg: Toast.makeText(MainActivity.this, "下载完成,马上安装", Toast.LENGTH_SHORT).show(); // 对下载的APK文件进行安装 String filename = FileUtil.getFileName(url); String str = "/myfile/" + filename; // 文件的全路径 String fileName = Environment.getExternalStorageDirectory() + str; Intent intent = new Intent(Intent.ACTION_VIEW); // 设置intent的data和Type属性。 intent.setDataAndType(Uri.fromFile(new File(fileName)), "application/vnd.android.package-archive"); // 跳转到安装页面 startActivity(intent); break; } super.handleMessage(msg); } }; }