很久沒有更新部落格了,最近公司的項目也沒那麼趕了,就照着慕課網的視訊,把斷點續傳的代碼敲了一遍,,調了半天,其中的坑也隻有自己敲過才知道.為了今後友善,我現在把所有的代碼都粘在下面了.
運作的效果如下:

這個才是
首先是我的代碼目錄結構
FileInfos主要是記錄要下載下傳的檔案資訊
private int id;
private String url;
private String fileName;
private int length;
private int finished;
ThreadInfo類是記錄線程資訊
private int id;
private String url;
private int start;
private int end;
private int finished;
DBHelper建立我的資料庫,單例模式
private static final String DB_NAME="download.db";
public static DBHelper helper;
private static String SQL_CREATE="create table if not exists thread_info(_id integer primary key autoincrement,thread_id integer," +
"url text,start integer,end integer,finished integer)";
private static String SQL_DROP="drop table if exists thread_info";
public static synchronized DBHelper getInstance(Context mContext)
{
if (helper==null)
{
helper=new DBHelper(mContext,DB_NAME,null,);
}
return helper;
}
private DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
**資料通路接口的實作
* Created by Administrator on //
*/
public class ThreadDaoImp implements ThreadDao{
private DBHelper helper;
public ThreadDaoImp(Context context) {
helper=DBHelper.getInstance(context);
}
@Override
public void insertThread(ThreadInfos threadInfos) {
SQLiteDatabase db = helper.getReadableDatabase();
db.execSQL("insert into thread_info(thread_id,url,start,end,finished) values (?,?,?,?,?)",
new Object[]{threadInfos.getId(),threadInfos.getUrl(),threadInfos.getStart(),threadInfos.getEnd(),threadInfos.getFinished()});
db.close();
}
@Override
public void deleteThread(String url, int thredId) {
SQLiteDatabase db = helper.getReadableDatabase();
db.execSQL("delete from thread_info where url= ? and thread_id= ?",
new Object[]{url,thredId});
db.close();
}
@Override
public void updateThread(String url, int threadId, int finished) {
SQLiteDatabase db = helper.getReadableDatabase();
db.execSQL("update thread_info set finished = ? where url= ? and thread_id= ?",
new Object[]{finished,url,threadId});
db.close();
}
@Override
public List<ThreadInfos> getThreads(String url) {
SQLiteDatabase db = helper.getReadableDatabase();
List<ThreadInfos> list=new ArrayList<>();
Cursor cursor = db.rawQuery("select * from thread_info where url= ? ",
new String[]{url});
while (cursor.moveToNext())
{
ThreadInfos threadInfos = new ThreadInfos();
threadInfos.setId(cursor.getInt(cursor.getColumnIndex("thread_id")));
threadInfos.setUrl(cursor.getString(cursor.getColumnIndex("url")));
threadInfos.setStart(cursor.getInt(cursor.getColumnIndex("start")));
threadInfos.setEnd(cursor.getInt(cursor.getColumnIndex("end")));
threadInfos.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
list.add(threadInfos);
}
cursor.close();
db.close();
return list;
}
@Override
public boolean isExists(String url, int threadId) {
SQLiteDatabase db = helper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from thread_info where url= ? and thread_id= ?",
new String[]{url,threadId+""});
boolean exists=cursor.moveToNext();
cursor.close();
db.close();
return exists;
}
}
/**下載下傳任務類
* Created by Administrator on 2017/7/19.
*/
public class DownloadTask {
private Context context;
private FileInfos fileInfos;
private ThreadDaoImp threadDaoImp;
private int mFinished=;
public boolean isPaused;
public DownloadTask(Context context, FileInfos fileInfos) {
this.context = context;
this.fileInfos = fileInfos;
threadDaoImp=new ThreadDaoImp(context);
}
public void download()
{
//讀取資料庫的線程資訊
List<ThreadInfos> list = threadDaoImp.getThreads(fileInfos.getUrl());
ThreadInfos threadInfos=null;
if (list.size()==)
{
//初始化線程資訊對象
threadInfos = new ThreadInfos(,fileInfos.getUrl(),,fileInfos.getLength(),);
//建立子線程進行下載下傳
new DownloadThread(threadInfos).start();
}
else
{
for (int i = ; i < list.size(); i++) {
threadInfos=list.get(i);
new DownloadThread(threadInfos).start();
}
}
}
//下載下傳線程
class DownloadThread extends Thread{
private ThreadInfos threadInfos;
public DownloadThread(ThreadInfos threadInfos) {
this.threadInfos = threadInfos;
}
@Override
public void run() {
super.run();
//先資料庫插入線程資訊
if (!threadDaoImp.isExists(threadInfos.getUrl(),threadInfos.getId()))
{
threadDaoImp.insertThread(threadInfos);
}
RandomAccessFile raf=null;
try {
URL url = new URL(threadInfos.getUrl());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//conn.connect();
int length=-;
//設定下載下傳位置
int start=threadInfos.getStart()+threadInfos.getFinished();
conn.setRequestProperty("Range","bytes="+start+"-"+threadInfos.getEnd());
//設定檔案寫入位置
File file = new File(DownloadService.DOWNLOAD_PATH,fileInfos.getFileName());
raf = new RandomAccessFile(file, "rwd");
raf.seek(start);
Intent intent = new Intent();
intent.setAction(DownloadService.ACTION_UPDATE);
mFinished+=threadInfos.getFinished();
if (conn.getResponseCode()==)
{
//開始下載下傳
//讀取資料
InputStream input = conn.getInputStream();
byte[] bytes = new byte[*];
long time=;
while ((length=input.read(bytes))!=-)
{
//寫入檔案
raf.write(bytes,,length);
//把下載下傳進度通過廣播發送給activity
mFinished+=length;
if (mFinished>=fileInfos.getLength())
{
mFinished=fileInfos.getLength();
}
if (System.currentTimeMillis()-time>)
{
time=System.currentTimeMillis();
intent.putExtra("progress",mFinished*/fileInfos.getLength());
context.sendBroadcast(intent);
}
//在下載下傳暫停時,儲存下載下傳進度
if (isPaused)
{
threadDaoImp.updateThread(threadInfos.getUrl(),threadInfos.getId(),mFinished);
return;
}
}
//下載下傳完成後,删除線程資訊
threadDaoImp.deleteThread(threadInfos.getUrl(),threadInfos.getId());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (raf!=null)
{
raf.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
/**資料庫通路接口
* Created by Administrator on 2017/7/19.
*/
public interface ThreadDao {
//插入線程資訊
public void insertThread(ThreadInfos threadInfos);
//删除線程
public void deleteThread(String url,int thredId);
//更新線程下載下傳進度
public void updateThread(String url,int threadId,int finished);
//查詢線程資訊
public List<ThreadInfos> getThreads(String url);
//線程資訊是否存在
public boolean isExists(String url,int threadId);
}
/**
* Created by Administrator on 2017/7/19.
*/
public class DownloadService extends Service{
public static final String DOWNLOAD_PATH= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()
+ File.separator+"demo";
public static final String ACTION_START="ACTION_START";
public static final String ACTION_STOP="ACTION_STOP";
public static final String ACTION_UPDATE="ACTION_UPDATE";
public static final int MSG_INIT=;
DownloadTask downloadTask;
public Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what)
{
case :
FileInfos fileInfos= (FileInfos) msg.obj;
Log.d("==handler====","======="+fileInfos.toString());
//啟動下載下傳任務
downloadTask = new DownloadTask(DownloadService.this, fileInfos);
downloadTask.download();
break;
default:
break;
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//擷取從activity中傳遞過來的資訊
if (ACTION_START.equals(intent.getAction()))
{
FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo");
Log.d("==start====","======"+fileInfo.toString());
new InitThread(fileInfo).start();
}
else if (ACTION_STOP.equals(intent.getAction()))
{
FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo");
Log.d("==stop====","======"+fileInfo.toString());
if (downloadTask!=null)
{
downloadTask.isPaused=true;
}
}
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
class InitThread extends Thread{
FileInfos fileInfos;
public InitThread(FileInfos fileInfos) {
this.fileInfos = fileInfos;
}
@Override
public void run() {
super.run();
RandomAccessFile raf=null;
try {
//連接配接網絡檔案
URL url = new URL(fileInfos.getUrl());
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
int length=-;
if (conn.getResponseCode()==)
{
//獲得檔案長度
length=conn.getContentLength();
if (length<=)
{
return;
}
File dir=new File(DOWNLOAD_PATH);
if (!dir.exists())
{
dir.mkdirs();
}
//在本地建立檔案
File file=new File(dir,fileInfos.getFileName());
raf = new RandomAccessFile(file, "rwd");
//設定檔案長度
raf.setLength(length);
}
fileInfos.setLength(length);
Message message = handler.obtainMessage();
message.what=MSG_INIT;
message.obj=fileInfos;
handler.sendMessage(message);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (raf!=null)
{
raf.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
TextView textView;
ProgressBar progressBar;
Button start_bt,pause_bt;
FileInfos fileInfos;
MyBroadCastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView= (TextView) findViewById(R.id.textView);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
start_bt= (Button) findViewById(R.id.start_bt);
pause_bt= (Button) findViewById(R.id.pause_bt);
initListener();
initFileInfo();
initData();
}
private void initData() {
//注冊廣播
receiver = new MyBroadCastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DownloadService.ACTION_UPDATE);
registerReceiver(receiver,intentFilter);
progressBar.setMax();
textView.setText(fileInfos.getFileName());
}
private void initFileInfo() {
//http://down.shouji.kuwo.cn/star/mobile/KuwoPlayerV3_ar_8.5.0.2_kw.apk
//http://www.imooc.com/video/7052
fileInfos = new FileInfos(, "http://down.shouji.kuwo.cn/star/mobile/KuwoPlayerV3_ar_8.5.0.2_kw.apk",
"kuwo.apk", , );
}
private void initListener() {
start_bt.setOnClickListener(this);
pause_bt.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId())
{
case R.id.start_bt:
Intent intentStart = new Intent(this, DownloadService.class);
intentStart.setAction(DownloadService.ACTION_START);
intentStart.putExtra("fileInfo",fileInfos);
startService(intentStart);
break;
case R.id.pause_bt:
Intent intentStop = new Intent(this, DownloadService.class);
intentStop.setAction(DownloadService.ACTION_STOP);
intentStop.putExtra("fileInfo",fileInfos);
startService(intentStop);
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
class MyBroadCastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if (DownloadService.ACTION_UPDATE.equals(intent.getAction()))
{
int progress = intent.getIntExtra("progress", -);
if (-!=progress)
{
progressBar.setProgress(progress);
}
}
}
}
}
其實還有個bug一直沒解決,進度條在檔案下載下傳完成後,并沒有走滿,而且我在公有目錄下建立的檔案夾的時間顯示是///,,,如果解決了,記得給我留言告我一聲啊!
這裡寫代碼片