很久没有更新博客了,最近公司的项目也没那么赶了,就照着慕课网的视频,把断点续传的代码敲了一遍,,调了半天,其中的坑也只有自己敲过才知道.为了今后方便,我现在把所有的代码都粘在下面了.
运行的效果如下:
这个才是
首先是我的代码目录结构
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,1);
}
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 2017/7/19.
*/
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=0;
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()==0)
{
//初始化线程信息对象
threadInfos = new ThreadInfos(0,fileInfos.getUrl(),0,fileInfos.getLength(),0);
//创建子线程进行下载
new DownloadThread(threadInfos).start();
}
else
{
for (int i = 0; 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=-1;
//设置下载位置
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()==206)
{
//开始下载
//读取数据
InputStream input = conn.getInputStream();
byte[] bytes = new byte[1024*4];
long time=0;
while ((length=input.read(bytes))!=-1)
{
//写入文件
raf.write(bytes,0,length);
//把下载进度通过广播发送给activity
mFinished+=length;
if (mFinished>=fileInfos.getLength())
{
mFinished=fileInfos.getLength();
}
if (System.currentTimeMillis()-time>300)
{
time=System.currentTimeMillis();
intent.putExtra("progress",mFinished*100/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=0;
DownloadTask downloadTask;
public Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what)
{
case 0:
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=-1;
if (conn.getResponseCode()==200)
{
//获得文件长度
length=conn.getContentLength();
if (length<=0)
{
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(50);
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(0, "http://down.shouji.kuwo.cn/star/mobile/KuwoPlayerV3_ar_8.5.0.2_kw.apk",
"kuwo.apk", 0, 0);
}
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", -1);
if (-1!=progress)
{
progressBar.setProgress(progress);
}
}
}
}
}
其实还有个bug一直没解决,进度条在文件下载完成后,并没有走满,而且我在公有目录下新建的文件夹的时间显示是2012/00/00/00,,,如果解决了,记得给我留言告我一声啊!
这里写代码片