这个多线程断点续传下载Demo是学习Android第五天的第一个项目Demo,主要是将远程url的地址一样多线程的方式现在下来
1)在编写程序之前先编写下载文件的线程类FIleDownloader
package com.example.mutithreadfiledowloader.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import com.example.mutithreadfiledowloader.MainActivity;
public class FileDownloader extends Thread {
private long startPoint;
private long endPoint;
private String fileurl;
private int tid;
private String dir;
private boolean flag;
public FileDownloader(long startPoint, long endPoint, String fileurl,
int tid, String dir) {
super();
this.startPoint = startPoint;
this.endPoint = endPoint;
this.fileurl = fileurl;
this.tid = tid;
this.dir = dir;
}
@Override
public void run() {
long kaishi = startPoint;
try {
File tidcfg = new File(this.dir + this.tid + ".txt");
if (!tidcfg.exists()) {// 线程对应的配置文件不存在,创建配置文件,写入开始位置
OutputStream os = new FileOutputStream(tidcfg);
os.write((startPoint + "").getBytes("utf-8"));
os.flush();
os.close();
} else {
try {
String sp = getText(tidcfg);
if (!("".equals(sp) || sp == null)) {
if (kaishi < Long.parseLong(sp))
startPoint = Long.parseLong(sp);
System.out.println("线程id=" + tid + "开始位置:" + sp
+ ", 原本开始位置:" + kaishi);
synchronized (MainActivity.class) {
MainActivity.PROGRESS += (startPoint - kaishi);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 得到服务器返回的输出流作为我们的输入流
if (startPoint < endPoint) {
URL url = new URL(fileurl);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
// 设置得到文件的数据范围
conn.setRequestProperty("Range", "bytes=" + startPoint + "-"
+ endPoint);
conn.setRequestMethod("GET");
conn.setReadTimeout(50000);
// 设置提交使用的浏览器客户端参数 火狐提交
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0");
InputStream is = conn.getInputStream();
RandomAccessFile file = new RandomAccessFile(getFileName(),
"rwd");
byte[] buffer = new byte[1024 * 32];
int len;
file.seek(startPoint);
while ((len = is.read(buffer)) != -1) {
file.write(buffer, 0, len);
startPoint+=len;
writeText(tidcfg, startPoint + "");
MainActivity.PROGRESS += len;
}
is.close();
file.close();
System.out.println("线程id=" + this.tid + "下载完毕,下载范围:"
+ startPoint + "(" + kaishi + ")------->" + endPoint);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public long getStartPoint() {
return startPoint;
}
public void setStartPoint(long startPoint) {
this.startPoint = startPoint;
}
public long getEndPoint() {
return endPoint;
}
public void setEndPoint(long endPoint) {
this.endPoint = endPoint;
}
public String getFileurl() {
return fileurl;
}
public void setFileurl(String fileurl) {
this.fileurl = fileurl;
}
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
public String getFileName() {
int start = fileurl.lastIndexOf("/") + 1;
if (dir.endsWith(File.separator)) {
return dir + fileurl.substring(start);
}
return dir + File.separator + fileurl.substring(start);
}
public String getDir() {
return dir;
}
public void setDir(String dir) {
this.dir = dir;
}
public String getText(File file) throws Exception {
InputStream is = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len1 = 0;
while ((len1 = is.read(bytes)) != -1) {
bos.write(bytes, 0, len1);
}
is.close();
bos.flush();
bos.close();
return new String(bos.toByteArray(), "utf-8");
}
public void writeText(File file, String str) throws Exception {
OutputStream os = new FileOutputStream(file);
os.write(str.getBytes("utf-8"));
os.flush();
os.close();
}
}
2)配置strings.xml和配置config.xml
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">MutiThreadFIleDowloader</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="tv_title">闪 公司多线程文件下载工具</string>
<string name="et_input_url">输入文件的下载地址</string>
<string name="btn_value">闪下文件</string>
</resources>
config.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="yellowurl">http://media.tumblr.com/535e3eb370136fea9ab4c9d433d442b9/tumblr_n0y7q5ACMZ1sfs9q2o1_1280.jpg</string>
<string name="imgurl">http://img1.gtimg.com/9/967/96712/9671283_980x1200_292.jpg</string>
<string name="apkurl">http://appdl.hicloud.com/dl/appdl/application/apk/a2/a2731b285b104f15b1adc6d3a6c493e9/com.tencent.pao.1405161227.apk</string>
</resources>
3)开发界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/tv_title" />
<EditText
android:id="@+id/et_input_url"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/et_input_url"
android:inputType="textUri" />
<ProgressBar
android:id="@+id/pbar_show"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|center_vertical" >
<Button
android:id="@+id/btn_download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/btn_value" >
</Button>
</LinearLayout>
<ImageView
android:id="@+id/iv_show"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="fill_vertical|fill_horizontal"
android:scaleType="fitCenter" />
</LinearLayout>
4)MainAcrivity相关的业务逻辑
package com.example.mutithreadfiledowloader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import com.example.mutithreadfiledowloader.util.FileDownloader;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends Activity implements OnClickListener {
private EditText et_url;
private Button btn_download;
private ProgressBar pb;
ImageView iv_show;
public static long PROGRESS = 0;
private long filesize;
private Handler handler = new Handler() {
@Override
public void handleMessage(android.os.Message msg) {
System.out.println(msg.obj);
pb.setProgress(Integer.parseInt(msg.obj.toString()));
super.handleMessage(msg);
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_url = (EditText) findViewById(R.id.et_input_url);
btn_download = (Button) findViewById(R.id.btn_download);
iv_show = (ImageView) findViewById(R.id.iv_show);
pb = (ProgressBar) findViewById(R.id.pbar_show);
btn_download.setOnClickListener(this);
et_url.setText(getResources().getString(R.string.apkurl));
pb.showContextMenu();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
String uri = et_url.getText().toString().trim();
String bitmap = "";
boolean flag = true;
switch (v.getId()) {
case R.id.btn_download:
// 设置下载线程的个数
int totals = 10;
URL url;
try {
url = new URL(uri);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
String dir = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ File.separator
+ "DownFiles"
+ File.separator;
File dirs = new File(dir);
if (!dirs.exists()) {
dirs.mkdir();
System.out.println(dirs.exists() + "===========");
}
// 设置提交使用的浏览器客户端参数 火狐提交
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0");
int code = conn.getResponseCode();
filesize = 0;
RandomAccessFile file = new RandomAccessFile(dir
+ getFileName(uri), "rwd");
Toast.makeText(this, getFileName(uri), 1).show();
String str = "";
File f = new File(dir, "cfg.txt");
OutputStream os = new FileOutputStream(f);
if (code == 200) {
filesize = conn.getContentLength();
pb.setMax(Integer.parseInt(filesize + ""));
// 启动更新界面的线程
new Thread() {
@Override
public void run() {
while (true) {
try {
sleep(500);
android.os.Message msg = new Message();
msg.obj = PROGRESS;
System.out.println("PROGRESS========"
+ PROGRESS
+ "========================");
handler.sendMessage(msg);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}.start();
System.out.println(filesize + "=========max");
file.setLength(filesize);
long blocksize = filesize / totals;
for (int i = 0; i < totals; i++) {
long start = i * blocksize;
long end = (i + 1) * blocksize;
if (i == totals - 1) {
end = filesize;
}
str += i + "===" + start + "--->" + end;
System.out.println(i + "===" + start + "--->" + end);
Toast.makeText(this, dir, 1).show();
FileDownloader downloader = new FileDownloader(start,
end, uri, i, dir);
downloader.start();
}
}
os.write(str.getBytes());
os.flush();
os.close();
bitmap = "/mnt/sdcard/" + getFileName(uri);
File filex = new File(bitmap);
if (filex.exists()) {
Toast.makeText(this, "文件存在!", 1).show();
iv_show.setImageBitmap(BitmapFactory.decodeFile(bitmap));
}
} catch (Exception e) {
// TODO: handle exception
}
break;
default:
break;
}
}
public String getFileName(String fileurl) {
int start = fileurl.lastIndexOf("/") + 1;
return fileurl.substring(start);
}
}
总结:
这个Demo是用到的相关技术:
1.RandomAccessFile 类的相关API 。
2.根据Http协议得到服务器端返回内容的类型和内容的长度(ContentLength)。
3.根据传入Range 参数的start-end取出指定区间的数据。
4.安卓的广播机制。
5.将下载的信息配置到文件中从而做到断点续传。