android多线程断点下载,带进度条和百分比显示,断点下载的临时数据保存到SD卡的文本文档中,建议可以保存到本地数据库中,这样可以提高存取效率,从而提高系统性能。
效果:
打开软件:
下载中:
下载完毕:
附代码如下:
1 package com.yy.multiDownloadOfBreakPoint; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.InputStream; 6 import java.io.RandomAccessFile; 7 import java.net.HttpURLConnection; 8 import java.net.URL; 9 10 import android.app.Activity; 11 import android.os.Bundle; 12 import android.os.Handler; 13 import android.os.Message; 14 import android.text.TextUtils; 15 import android.view.View; 16 import android.widget.EditText; 17 import android.widget.ProgressBar; 18 import android.widget.TextView; 19 import android.widget.Toast; 20 /** 21 * 多线程断点下载实例 22 * @author YUANYUAN 23 * 24 */ 25 public class MainActivity extends Activity { 26 //下载所使用的线程数 27 protected static final int threadCount = 3; 28 //下载完毕的标记 29 public static final int downloadOver = 1; 30 //更新下载进度标记 31 public static final int UPDATE_PROGRESS = 0; 32 //下载资源的路径输入框 33 private EditText et_path; 34 //下载的进度条 35 private ProgressBar pb; 36 //进度显示 37 private TextView tv_pb; 38 //当前累计下载的数据 39 int curDownCount=0; 40 //当前活动的下载线程数 41 protected static int activeThread; 42 //加入消息处理机制 43 private Handler handler=new Handler(){ 44 @Override 45 public void handleMessage(Message msg) { 46 switch (msg.what) { 47 case downloadOver: 48 Toast.makeText(MainActivity.this, "文件已下载完毕!", Toast.LENGTH_LONG).show(); 49 tv_pb.setText("下载完成"); 50 break; 51 case UPDATE_PROGRESS: 52 //更新进度显示 53 tv_pb.setText("当前进度:"+(pb.getProgress()*100/pb.getMax())+"%"); 54 break; 55 default: 56 break; 57 } 58 } 59 }; 60 61 @Override 62 protected void onCreate(Bundle savedInstanceState) { 63 super.onCreate(savedInstanceState); 64 setContentView(R.layout.activity_main); 65 et_path=(EditText) findViewById(R.id.et_path); 66 et_path.setText("http://192.168.2.114:8080/sqlite.exe"); 67 pb=(ProgressBar) findViewById(R.id.pb); 68 tv_pb=(TextView) findViewById(R.id.tv_pb); 69 } 70 71 /** 72 * 开始下载 73 * @param view 74 */ 75 public void down(View view){ 76 //获取下载资源的路径 77 final String path=et_path.getText().toString().trim(); 78 //判断资源路径是否为空 79 if (TextUtils.isEmpty(path)) { 80 Toast.makeText(this, "请输入下载资源的路径", Toast.LENGTH_LONG).show(); 81 return; 82 } 83 //开启一个线程进行下载 84 new Thread(){ 85 public void run() { 86 try { 87 //构造URL地址 88 URL url=new URL(path); 89 //打开连接 90 HttpURLConnection conn=(HttpURLConnection) url.openConnection(); 91 //设置请求超时的时间 92 conn.setConnectTimeout(5000); 93 //设置请求方式 94 conn.setRequestMethod("GET"); 95 //获取相应码 96 int code=conn.getResponseCode(); 97 if (code==200) {//请求成功 98 //获取请求数据的长度 99 int length=conn.getContentLength(); 100 //设置进度条的最大值 101 pb.setMax(length); 102 //在客户端创建一个跟服务器文件大小相同的临时文件 103 RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd"); 104 //指定临时文件的长度 105 raf.setLength(length); 106 raf.close(); 107 //假设3个线程去下载资源 108 //平均每一个线程要下载的文件的大小 109 int blockSize=length/threadCount; 110 for (int threadId = 1; threadId <= threadCount; threadId++) { 111 //当前线程下载数据的开始位置 112 int startIndex=blockSize*(threadId-1); 113 //当前线程下载数据的结束位置 114 int endIndex=blockSize*threadId-1; 115 //确定最后一个线程要下载数据的最大位置 116 if (threadId==threadCount) { 117 endIndex=length; 118 } 119 //显示下载数据的区间 120 System.out.println("线程【"+threadId+"】开始下载:"+startIndex+"---->"+endIndex); 121 //开启下载的子线程 122 new DownloadThread(path, threadId, startIndex, endIndex).start(); 123 //当前下载活动的线程数加1 124 activeThread++; 125 System.out.println("当前活动的线程数:"+activeThread); 126 } 127 128 }else{//请求失败 129 System.out.println("服务器异常,下载失败!"); 130 } 131 } catch (Exception e) { 132 e.printStackTrace(); 133 System.out.println("服务器异常,下载失败!"); 134 } 135 }; 136 }.start(); 137 138 } 139 /** 140 * 下载文件的子线程 每一个文件都下载对应的数据 141 * @author YUANYUAN 142 * 143 */ 144 public class DownloadThread extends Thread{ 145 private String path; 146 private int threadId; 147 private int startIndex; 148 private int endIndex; 149 150 /** 151 * 构造方法 152 * @param path 下载文件的路径 153 * @param threadId 下载文件的线程 154 * @param startIndex 下载文件开始的位置 155 * @param endIndex 下载文件结束的位置 156 */ 157 public DownloadThread(String path, int threadId, int startIndex, 158 int endIndex) { 159 this.path = path; 160 this.threadId = threadId; 161 this.startIndex = startIndex; 162 this.endIndex = endIndex; 163 } 164 165 166 167 @Override 168 public void run() { 169 //构造URL地址 170 try { 171 172 File tempFile=new File("sdcard/"+threadId+".txt"); 173 //检查记录是否存在,如果存在读取数据,设置真实下载开始的位置 174 if (tempFile.exists()) { 175 FileInputStream fis=new FileInputStream(tempFile); 176 byte[] temp=new byte[1024]; 177 int length=fis.read(temp); 178 //读取到已经下载的位置 179 int downloadNewIndex=Integer.parseInt(new String(temp, 0, length)); 180 //计算出已经下载的数据长度 181 int areadyDown=downloadNewIndex-startIndex; 182 //累加已经下载的数据量 183 curDownCount+=areadyDown; 184 //设置进度条已经下载的数据量 185 pb.setProgress(curDownCount); 186 //设置重新开始下载的开始位置 187 startIndex=downloadNewIndex; 188 fis.close(); 189 //显示真实下载数据的区间 190 System.out.println("线程【"+threadId+"】真实开始下载数据区间:"+startIndex+"---->"+endIndex); 191 } 192 193 URL url = new URL(path); 194 HttpURLConnection conn=(HttpURLConnection) url.openConnection(); 195 conn.setConnectTimeout(5000); 196 conn.setRequestMethod("GET"); 197 //设置请求属性,请求部分资源 198 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); 199 int code=conn.getResponseCode(); 200 if (code==206) {//下载部分资源,正常返回的状态码为206 201 InputStream is=conn.getInputStream();//已经设置了请求的位置,所以返回的是对应的部分资源 202 //构建随机访问文件 203 RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd"); 204 //设置 每一个线程随机写文件开始的位置 205 raf.seek(startIndex); 206 //开始写文件 207 int len=0; 208 byte[] buffer=new byte[1024]; 209 //该线程已经下载数据的长度 210 int total=0; 211 212 while((len=is.read(buffer))!=-1){//读取输入流 213 //记录当前线程已下载数据的长度 214 RandomAccessFile file=new RandomAccessFile("sdcard/"+threadId+".txt","rwd"); 215 raf.write(buffer,0,len);//写文件 216 total+=len;//更新该线程已下载数据的总长度 217 System.out.println("线程【"+threadId+"】已下载数据:"+(total+startIndex)); 218 //将已下载数据的位置记录写入到文件 219 file.write((startIndex+total+"").getBytes()); 220 //累加已经下载的数据量 221 curDownCount+=len; 222 //更新进度条【进度条的更新可以在非UI线程直接更新,具体见底层源代码】 223 pb.setProgress(curDownCount); 224 225 //更新下载进度 226 Message msg=Message.obtain(); 227 msg.what=UPDATE_PROGRESS; 228 handler.sendMessage(msg); 229 230 file.close(); 231 } 232 is.close(); 233 raf.close(); 234 //提示下载完毕 235 System.out.println("线程【"+threadId+"】下载完毕"); 236 } 237 } catch (Exception e) { 238 e.printStackTrace(); 239 System.out.println("线程【"+threadId+"】下载出现异常!!"); 240 }finally{ 241 //活动的线程数减少 242 activeThread--; 243 if (activeThread==0) { 244 for (int i = 1; i <= threadCount; i++) { 245 File tempFile=new File("sdcard/"+i+".txt"); 246 tempFile.delete(); 247 } 248 System.out.println("下载完毕,已清除全部临时文件"); 249 //界面消息提示下载完毕 250 Message msg=new Message(); 251 msg.what=downloadOver; 252 handler.sendMessage(msg); 253 } 254 } 255 256 } 257 } 258 }