安卓(android)之實現斷點下載功能


一.創建實體類

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 +
'}';
}
}

2、創建數據庫

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;
}
}
3、創建下載服務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();
}
}
}
}
}
4、創建下載任務類

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();
}
}

}

}
 5、在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();
}
}
}
}
};
}
6、運行效果

相關文章
相關標籤/搜索