一.建立实体类
1.文件实体类
package com.example.zjw.myapplication.dao;
import java.io.Serializable;
/**
* 预下载文件实体类
* Created by Administrator on 2016/6/20.
*/
public class FileInfo implements Serializable {
//文件id
private int id;
//文件下载地址
private String url;
//文件名
private String name;
//文件长度
private int length;
//文件下载完成进度
private int finished;
public FileInfo(){}
public FileInfo(int id, String url, String name, int length, int finished) {
this.id = id;
this.url = url;
this.name = name;
this.length = length;
this.finished = finished;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getFinished() {
return finished;
}
public void setFinished(int finished) {
this.finished = finished;
}
@Override
public String toString() {
return "FileInfo{" +
"id=" + id +
", url='" + url + '\'' +
", name='" + name + '\'' +
", length=" + length +
", finished=" + finished +
'}';
}
}
2.线程实体类
package com.example.zjw.myapplication.dao;
import java.io.Serializable;
/**下载线程实体类
* Created by Administrator on 2016/6/20.
*/
public class ThreadInfo implements Serializable{
//线程id
private int id;
//下载地址
private String url;
//下载的开始位置
private int start;
//下载的结束位置
private int end;
//下载完成进度
private int finished;
public ThreadInfo(){}
public ThreadInfo(int id, String url, int start, int end, int finished) {
this.id = id;
this.url = url;
this.start = start;
this.end = end;
this.finished = finished;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public int getFinished() {
return finished;
}
public void setFinished(int finished) {
this.finished = finished;
}
@Override
public String toString() {
return "ThreadInfo{" +
"id=" + id +
", url='" + url + '\'' +
", start=" + start +
", end=" + end +
", finished=" + finished +
'}';
}
}
二、建立数据库
1.建立数据库帮助类
package com.example.zjw.myapplication.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**数据库帮助类
* Created by Administrator on 2016/6/20.
*/
public class DBHelper extends SQLiteOpenHelper {
//数据库名称
private static final String DB_NAME="download.db";
//数据库版本
private static final int VERSION=1;
//创建数据库表sql语句
private static final String SQL_CREATE="create table thread_info(id integer primary key autoincrement,thread_id integer,url text,start integer,end integer,finished integer)";
//删除数据库表语句
private static final String SQL_DROP="drop table if exists thread_info";
public DBHelper(Context context) {
super(context,DB_NAME,null,VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(SQL_DROP);
}
}
2.建立数据库访问接口
package com.example.zjw.myapplication.db;
import com.example.zjw.myapplication.dao.ThreadInfo;
import java.util.List;
/**
* 数据访问接口
* Created by Administrator on 2016/6/20.
*/
public interface ThreadDao {
void addThreadInfo(ThreadInfo threadInfo);
void deleteThreadInfo(String url,int thread_id);
void updateThreadInfo(String url,int thread_id,int finished);
List<ThreadInfo>getThreadInfo(String url);
boolean findThreadInfo(String url,int thread_id);
}
3.实现数据库访问接口
package com.example.zjw.myapplication.db;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.example.zjw.myapplication.dao.ThreadInfo;
import java.util.ArrayList;
import java.util.List;
/**数据库接口访问实现
* Created by Administrator on 2016/6/20.
*/
public class ThreadDaoImpl implements ThreadDao {
private DBHelper dbHelper =null;
public ThreadDaoImpl(Context context) {
this.dbHelper = new DBHelper(context);
}
@Override
public void addThreadInfo(ThreadInfo threadInfo) {
SQLiteDatabase writableDatabase = dbHelper.getWritableDatabase();
writableDatabase.execSQL("insert into thread_info(thread_id,url,start,end,finished) values(?,?,?,?,?)",new Object[]{
threadInfo.getId(),threadInfo.getUrl(),threadInfo.getStart(),threadInfo.getEnd(),threadInfo.getFinished()});
writableDatabase.close();
}
@Override
public void deleteThreadInfo(String url, int thread_id) {
SQLiteDatabase writableDatabase = dbHelper.getWritableDatabase();
writableDatabase.execSQL("delete from thread_info where url=?and thread_id=?", new Object[]{url,thread_id});
writableDatabase.close();
}
@Override
public void updateThreadInfo(String url, int thread_id,int finished) {
SQLiteDatabase writableDatabase = dbHelper.getWritableDatabase();
writableDatabase.execSQL("update thread_info set finished=? where url=?and thread_id=?", new Object[]{finished,url,thread_id});
writableDatabase.close();
}
@Override
public List<ThreadInfo> getThreadInfo(String url) {
SQLiteDatabase readableDatabase = dbHelper.getReadableDatabase();
List<ThreadInfo>list = new ArrayList<>();
Cursor cursor = readableDatabase.rawQuery("select * from thread_info where url=?",new String[]{url});
while (cursor.moveToNext()){
ThreadInfo thread =new ThreadInfo();
thread.setId(cursor.getInt(cursor.getColumnIndex("thread_id")));
thread.setUrl(cursor.getString(cursor.getColumnIndex("url")));
thread.setStart(cursor.getInt(cursor.getColumnIndex("start")));
thread.setEnd(cursor.getInt(cursor.getColumnIndex("end")));
thread.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
list.add(thread);
}
readableDatabase.close();
cursor.close();
return list;
}
@Override
public boolean findThreadInfo(String url, int thread_id) {
SQLiteDatabase readableDatabase = dbHelper.getReadableDatabase();
List<ThreadInfo>list = new ArrayList<>();
Cursor cursor = readableDatabase.rawQuery("select * from thread_info where url=? and thread_id=?",new String[]{url,thread_id+""});
boolean b = cursor.moveToNext();
readableDatabase.close();
cursor.close();
return b;
}
}
三、建立下载服务Service
package com.example.zjw.myapplication.service;
import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import com.example.zjw.myapplication.dao.FileInfo;
import com.example.zjw.myapplication.dao.ThreadInfo;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* 下载文件服务
*/
public class DownloadService extends Service {
public static final String ACTION_START="ACTION_START";
public static final String ACTION_STOP="ACTION_STOP";
public static final int MSG_INIT=10;
public static final String UPDATE="UPDATE";
private DownloadTask task;
public static String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/MyDownload";
public DownloadService() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//获取activity传来的参数
if(ACTION_START.equals(intent.getAction())){
FileInfo fileInfo = (FileInfo)intent.getSerializableExtra("fileInfo");
Log.d("TAG-----", "onStartCommand: 开始下载"+fileInfo.toString());
new Thread(new InitThread(fileInfo)).start();
}
if(ACTION_STOP.equals(intent.getAction())){
Serializable fileInfo = (FileInfo)intent.getSerializableExtra("fileInfo");
Log.d("TAG-----", "onStartCommand: 暂停下载"+fileInfo);
if(task!=null){
task.isDownload=true;
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
private Handler handler =new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case MSG_INIT:
FileInfo fileInfo = (FileInfo) msg.obj;
Log.d("TAG", "handleMessage:-------------> "+fileInfo);
//启动下载任务
task = new DownloadTask(fileInfo,DownloadService.this);
task.download();
break;
}
}
};
/**
* 初始化子线程
*/
private class InitThread implements Runnable{
private FileInfo fileInfo;
private RandomAccessFile ws;
public InitThread(FileInfo threadInfo){
this.fileInfo=threadInfo;
}
@Override
public void run() {
HttpURLConnection conn=null;
try {
URL url =new URL(fileInfo.getUrl());
conn= (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setRequestMethod("GET");
conn.connect();
int length=-1;
if(conn.getResponseCode()==HttpURLConnection.HTTP_OK){
length=conn.getContentLength();//获取下载文件长度
}
if(length<=0){
return;
}
//创建文件夹
File dir = new File(path);
if(!dir.exists()){
dir.mkdir();
}
File file = new File(dir,fileInfo.getName());
this.ws = new RandomAccessFile(file,"rwd");
ws.setLength(length);
fileInfo.setLength(length);
Message msg =new Message();
msg.obj=fileInfo;
msg.what=MSG_INIT;
handler.sendMessage(msg);
} catch (Exception e) {
e.printStackTrace();
}finally {
conn.disconnect();
try {
if(ws!=null)
ws.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
四、建立下载任务类
package com.example.zjw.myapplication.service;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.example.zjw.myapplication.dao.FileInfo;
import com.example.zjw.myapplication.dao.ThreadInfo;
import com.example.zjw.myapplication.db.ThreadDao;
import com.example.zjw.myapplication.db.ThreadDaoImpl;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
/**下载任务类
* Created by Administrator on 2016/6/20.
*/
public class DownloadTask {
private FileInfo fileInfo=null;
private Context context;
private ThreadDao threadDao;
public boolean isDownload;
private int finished;
public DownloadTask(FileInfo fileInfo, Context context) {
this.fileInfo = fileInfo;
this.context = context;
this.threadDao=new ThreadDaoImpl(context);
}
//下载文件
public void download(){
//读取数据库线程信息
List<ThreadInfo> threadInfos = threadDao.getThreadInfo(fileInfo.getUrl());
ThreadInfo threadInfo =null;
if(threadInfos.size()==0){
threadInfo =new ThreadInfo(0,fileInfo.getUrl(),0,fileInfo.getLength(),0);
}else {
threadInfo=threadInfos.get(0);
Log.d("TAG----------", threadInfo.getEnd()+"---download: ---"+threadInfo.getFinished());
}
//创建子线程下载文件
new Thread(new DownloadThread(threadInfo)).start();
}
//实现下载
private class DownloadThread implements Runnable{
private ThreadInfo threadInfo;
public DownloadThread(ThreadInfo threadInfo) {
this.threadInfo = threadInfo;
}
@Override
public void run() {
//向数据库插入线程信息
if(!threadDao.findThreadInfo(threadInfo.getUrl(),threadInfo.getId())){
threadDao.addThreadInfo(threadInfo);
}
try {
URL url =new URL(threadInfo.getUrl());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5*1000);
//设置下载位置
int start=threadInfo.getStart()+threadInfo.getFinished();
conn.setRequestProperty("Range","bytes="+start+"-"+threadInfo.getEnd());
//设置文件写入位置
File file =new File(DownloadService.path,fileInfo.getName());
RandomAccessFile ws = new RandomAccessFile(file,"rwd");
ws.seek(start);
//开始下载
//注意别写成200了不然就无法完成断点下载,206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它(HTTP 1.1新)。
if(conn.getResponseCode()==206){
InputStream inputStream = conn.getInputStream();
byte[] data = new byte[1024];
int len=-1;
Intent intent=new Intent(DownloadService.UPDATE);
finished=threadInfo.getFinished();
//读取文件
while ((len=inputStream.read(data))!=-1){
//写入文件
ws.write(data,0,len);
//发送广播更新进度条
finished+=len;
intent.putExtra("finished", finished * 100 / fileInfo.getLength());
context.sendBroadcast(intent);
Log.d("TAG----******-----", threadInfo.getEnd()+"---download: ---"+finished);
//下载暂停,保存下载进度
if(isDownload){
threadDao.updateThreadInfo(threadInfo.getUrl(),threadInfo.getId(),finished);
return;
}
}
//删除线程信息
threadDao.deleteThreadInfo(threadInfo.getUrl(),threadInfo.getId());
ws.close();
inputStream.close();
conn.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
五、在acticity中调用
package com.example.zjw.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.example.zjw.myapplication.dao.FileInfo;
import com.example.zjw.myapplication.dao.ThreadInfo;
import com.example.zjw.myapplication.db.ThreadDaoImpl;
import com.example.zjw.myapplication.service.DownloadService;
import java.util.List;
public class DownloadActivity extends AppCompatActivity {
private ProgressBar progressBar;
private TextView tv;
private boolean isDownload;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
this.progressBar= (ProgressBar) this.findViewById(R.id.progressBar);
progressBar.setMax(100);
this.tv = (TextView) this.findViewById(R.id.progressTv);
//开始下载
findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(!isDownload){
FileInfo fileInfo =new FileInfo(0,"http://b.hiphotos.baidu.com/image/pic/item/0823dd54564e925838c205c89982d158ccbf4e26.jpg","110.jpg",0,0);
Intent intent = new Intent(DownloadActivity.this,DownloadService.class);
intent.setAction(DownloadService.ACTION_START);
intent.putExtra("fileInfo",fileInfo);
startService(intent);
isDownload=true;
}
}
});
//停止下载
findViewById(R.id.stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// downloadFileUtil.setIsDownload(false);
isDownload=false;
FileInfo fileInfo =new FileInfo(0,"http://b.hiphotos.baidu.com/image/pic/item/0823dd54564e925838c205c89982d158ccbf4e26.jpg","112.jpg",0,0);
Intent intent = new Intent(DownloadActivity.this,DownloadService.class);
intent.setAction(DownloadService.ACTION_STOP);
intent.putExtra("fileInfo",fileInfo);
startService(intent);
}
});
init();
}
//初始化
private void init() {
//当打开下载界面显示历史下载进度
ThreadDaoImpl dao =new ThreadDaoImpl(this);
List<ThreadInfo> threadInfos = dao.getThreadInfo("http://b.hiphotos.baidu.com/image/pic/item/0823dd54564e925838c205c89982d158ccbf4e26.jpg");
if(threadInfos.size()>0){
ThreadInfo threadInfo = threadInfos.get(0);
int value=threadInfo.getFinished()*100/threadInfo.getEnd();
progressBar.setProgress(value);
tv.setText(value+"%");
}
//注册广播
IntentFilter intent = new IntentFilter();
intent.addAction(DownloadService.UPDATE);
registerReceiver(reciver,intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(reciver);
}
BroadcastReceiver reciver =new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int finished = intent.getIntExtra("finished",-1);
if(finished!=-1){
if ( finished<=100) {
progressBar.setProgress( finished);
tv.setText( finished+"%");
if( finished==100){
isDownload=false;
Toast.makeText(DownloadActivity.this, "下载完成", Toast.LENGTH_SHORT).show();
}
}
}
}
};
}
六、运行效果