实现断点续传的思路
1.当客户端发出HTTP请求时如果请求头是需要获取整个文件数据,那么成功时从服务器端得到的响应码为200。如果只需要获取其中部分数据,成功时得到的响应码为206。
setRequestProperty(“Accept-Encoding”, “identity”);//避免得到的服务器端文件字节数为零
setRequestProperty(“Range”, “bytes=” + bytes + “-” + lastIndex); //分段请求头信息
2.使用RandomAccessFile创建一个与服务器端的文件大小相同的空文件。当按下暂停按钮后需要记录下当前文件指针所指位置,继续下载时从记录位置开始写入。下载完毕后删除记录文件。
3.将下载过程放在服务中并开启一个新线程。
MainActivity.java
package com.example.breakpointdownload;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Environment;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private com.daimajia.numberprogressbar.NumberProgressBar pb;
static final String MY_ACTION = "com.marszhou.breakpointdownload"; //自定义一个action
private int count = 0;
private Button bt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pb = (com.daimajia.numberprogressbar.NumberProgressBar) findViewById(R.id.pb);
pb.setMax(100); //设置进度条最大值
findViewById(R.id.bt_stop);
bt = (Button) findViewById(R.id.bt);
registBroadcastReceiver();
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (count % 2 == 0){
//开启一个服务执行下载任务
DlService.flag = false;
startService(new Intent(getApplicationContext(), DlService.class));
count ++;
bt.setText("暂停");
}
else { //暂停下载的业务逻辑
DlService.flag = true;
count ++;
bt.setText("下载");
}
}
});
Log.e("getFilesDir()", getFilesDir().getPath());
Log.e("Environment", Environment.getExternalStorageDirectory().getPath());
Log.e("package", getPackageName());
}
public void registBroadcastReceiver() { //动态注册广播接受器
IntentFilter intentFilter = new IntentFilter(MY_ACTION);
registerReceiver(new MyReceiver(), intentFilter);
}
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int value = intent.getIntExtra("value", 0);
switch (value) {
case 0xfffffffd:
Toast.makeText(getApplicationContext(), "网络连接异常!", Toast.LENGTH_LONG).show();
count --;
bt.setText("下载");
break;
case 0xfffffffe: //开始下载
Toast.makeText(getApplicationContext(), "开始下载...", Toast.LENGTH_SHORT).show();
break;
case 0xffffffff: //下载完成
stopService(new Intent(getApplicationContext(), DlService.class));
Toast.makeText(getApplicationContext(), "下载停止", Toast.LENGTH_SHORT).show();
break;
default:
pb.setProgress(value); //更新进度条
break;
}
}
}
}
DownloadService.java
package com.example.breakpointdownload;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class DlService extends Service {
static boolean flag = false;
@Override
public void onCreate() {
super.onCreate();
Log.i("service", "服务启动了");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
MyTask myTask = new MyTask();
myTask.execute();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("service", "服务销毁了");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
public class MyTask extends AsyncTask {
String MY_ACTION = MainActivity.MY_ACTION;
@Override
protected void onPostExecute(Object o) { //发送0xff表示下载完成
super.onPostExecute(o);
Intent in = new Intent(MY_ACTION);
in.putExtra("value", 0xffffffff);
sendBroadcast(in);
}
@Override
protected void onPreExecute() { //发送0x11表示开始下载
super.onPreExecute();
Intent in = new Intent(MY_ACTION);
in.putExtra("value", 0xfffffffe);
sendBroadcast(in);
}
@Override
protected Object doInBackground(Object[] params) { //执行下载任务
try {
File file = new File(Environment.getExternalStorageDirectory(), "163music.exe");
RandomAccessFile accessFile = new RandomAccessFile(file, "rw");
SharedPreferences sp = getSharedPreferences("index", Context.MODE_PRIVATE);
int bytes = sp.getInt("bytes", 0);
if (bytes <= 0) { //第一次下载
URL url = new URL("http://sw.bos.baidu.com/sw-search-sp/software/1fe4c5b865602/cloudmusicsetup_2.1.1.30494_baidupc.exe");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoInput(true);
urlConnection.setRequestProperty("Accept-Encoding", "identity"); //设置请求参数
urlConnection.setConnectTimeout(1000*10);
Log.e("code", urlConnection.getResponseCode() + "");
if (urlConnection.getResponseCode() == 200) {
int total = urlConnection.getContentLength(); //获取网络资源大小
accessFile.setLength(total);
int lastIndex = (int) file.length();
InputStream inputStream = urlConnection.getInputStream();
int i, count = 0;
byte buffer[] = new byte[1024];
while ((i = inputStream.read(buffer)) != -1) {
if (flag)
break;
count += i;
int progress = (int) (count * 100.0 / total);
accessFile.write(buffer, 0, i);
Intent in = new Intent(MY_ACTION);
in.putExtra("value", progress);
sendBroadcast(in);
}
Log.e("index中的内容", accessFile.getFilePointer() + "");
SharedPreferences.Editor editor = sp.edit();
editor.putInt("bytes", (int) accessFile.getFilePointer());
editor.commit();
if (count == lastIndex){ //删除计数文件
File file3= new File("/data/data/" + getPackageName() + "/shared_prefs","index.xml");
if (file3.exists())
file3.delete();
}
}
} else { //断点下载
// Log.e("index内容", index_str);
// int index = Integer.parseInt(index_str);
Log.e("index内容", bytes + "");
int lastIndex = (int) file.length(); //获取原始资源长度
Log.e("lastindex内容", lastIndex + "");
accessFile.seek(bytes);
URL url = new URL("http://sw.bos.baidu.com/sw-search-sp/software/1fe4c5b865602/cloudmusicsetup_2.1.1.30494_baidupc.exe");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoInput(true);
urlConnection.setRequestProperty("Accept-Encoding", "identity"); //设置请求参数
urlConnection.setRequestProperty("Range", "bytes=" + bytes + "-" + lastIndex); //设置分段下载的头信息。 Range:做分段数据请求用的。
urlConnection.setConnectTimeout(1000*10);
Log.e("code---", urlConnection.getResponseCode() + "");
if (urlConnection.getResponseCode() == 206) { //200:请求全部资源成功, 206代表部分资源请求成功
InputStream inputStream = urlConnection.getInputStream();
int i, count = bytes;
byte buffer[] = new byte[1024];
while ((i = inputStream.read(buffer)) != -1) {
if (flag)
break;
accessFile.write(buffer, 0, i);
count += i;
int progress = (int) (count * 100.0 / lastIndex);
Intent in = new Intent(MY_ACTION);
in.putExtra("value", progress);
sendBroadcast(in);
}
Log.e("lastIndex", String.valueOf(lastIndex));
Log.e("count", String.valueOf(count));
SharedPreferences.Editor editor = sp.edit();
editor.putInt("bytes", (int) accessFile.getFilePointer());
editor.commit();
if (count == lastIndex){ //删除计数文件
File file3= new File("/data/data/" + getPackageName() + "/shared_prefs","index.xml");
if (file3.exists())
file3.delete();
}
}
}
} catch (Exception e) {
Intent in = new Intent(MY_ACTION);
in.putExtra("value", 0xfffffffd);
sendBroadcast(in);
e.printStackTrace();
}
return null;
}
}
}
加上用户权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
效果如下: