Android实现多线程断点续传 本文实例为大家分享了Android实现多线程断点续传的具体代码,供大家参考,具体内容如下 多线程下载涉及到的知识点: 1.Service的使用:我们在Service中去下载文件:2.Thread的使用:Service本身不支持耗时操作,所以我们要去开启线程
本文实例为大家分享了Android实现多线程断点续传的具体代码,供大家参考,具体内容如下
多线程下载涉及到的知识点:
1、Service的使用:我们在Service中去下载文件;
2、Thread的使用:Service本身不支持耗时操作,所以我们要去开启线程;
3、Sqlite的使用:使用数据库来存储每个线程下载的文件的进度,和文件的下载情况;
4、权限:涉及到文件的读写就要用到权限;
5、BroadCastReceiver的使用:通过广播来更新下载进度;
6、线程池使用:使用线程池来管理线程,减少资源的浪费
7、HttpUrlConnection的使用:下载文件使用的
8、ListView和BaseAdapter的使用:下载列表的显示
9、RandomAccessFile使用
先解释一下我们要做什么:
1、我们现在有一个文件,然后要分成好几个线程去下载,那么我们需要将这个文件平分,然后分给各个线程去下载,而每个线程在下载的时候,你不一定啥时候点了暂停,那么就要记录我的下载进度,所以要用到数据库。
2、你可能又会问,怎么去知道谁下载哪呢?我们的HttpURLConnection可以通过他的setRequestProperty()方法设置下载范围,从哪开始到哪结束。
3、同样下载解决了,那么写文件呢,怎么往文件里面写呢,那么就要用到RandomAccessFile这个文件的特性了,从文件的任意位置开始写,是不是清晰了。
4、 还有问题就是怎么更新界面,用我们的广播,告诉什么时候去更新界面。
(实现的效果,是一个文件可以由多个线程下载,可以同时下载多个文件)
**这里需要注意:**不可以在获取长度后直接去下载文件,因为,我们获取文件长度的时候需要使用的请求码是200,如果我们想要分段去下载(也就是设置了connection.setRequestProperty(“Range”,“bytes=”"之后就是分段下载了)那么使用到的请求码是206。所以我们这里要将这两个请求分开来写,我就一开始将两个写到一起了,但是是不可以的会报错,更不要想着通过请求码来区分,这个就更错了
1、下面贴出***服务类***的代码:
这里的工作主要就是开启下载任务和停止下载任务,还有就是获取下载文件的长度,并创建本地文件并设置长度。
public class DownLoadService extends Service {
public static final int STATUS_START = 0;
public static final int STATUS_STOP = 1;
public static final String PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
private FileInfo mFileInfo;
//统一管理DownLoadTask,有个文件下载就有个DownLoadTask,所以使用Map去管理,主要控制暂停
private Map<Integer,Object> downtaskMap = new HashMap<>();
private DownLoadTask downLoadTask;
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
int status = intent.getIntExtra("status", 0);
if (status == STATUS_START) {
//开始下载
mFileInfo = (FileInfo) intent.getSerializableExtra("fileinfo");
DownLoadTask.sExecutorService.execute(new GetFileLenght(mFileInfo, this));
} else {
//暂停下载
mFileInfo = (FileInfo) intent.getSerializableExtra("fileinfo");
Log.e("---------->","mFileInfo:"+mFileInfo);
downLoadTask = (DownLoadTask) downtaskMap.get(mFileInfo.getId());
if(downLoadTask!=null){
downLoadTask.isPause = true;
}
}
}
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
/**
* 获得要下载的文件的长度,并创建本地文件
* 不能和下载的线程写在一起
*/
class GetFileLenght extends Thread {
private FileInfo fileInfo;
private Context context;
public GetFileLenght(FileInfo fileInfo, Context context) {
this.fileInfo = fileInfo;
this.context = context;
}
@Override
public void run() {
super.run();
HttpURLConnection conn = null;
RandomAccessFile raf = null;
try {
URL url = new URL(fileInfo.getUrl());
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
int length = -1;
if (conn.getResponseCode() == 200) {
length = conn.getContentLength();
if (length > 0) {
//创建本地文件
File file = new File(PATH, fileInfo.getFile_name());
raf = new RandomAccessFile(file, "rwd");
//设置本地文件的长度
raf.setLength(length);
fileInfo.setLength(length);
//开始下载
downLoadTask =new DownLoadTask(DownLoadService.this,fileInfo);
downLoadTask.down();
downtaskMap.put(fileInfo.getId(),downLoadTask);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.disconnect();
try {
if (raf != null) {
raf.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2、DownLoadTask的代码,也就是真正的核心的地方
这里的关系是一个FileInfo对应一个DownLoadTask,一个DownLoadTask对应着多个线程
package com.example.a_0102.mylearn.download;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 下载文件的内容
*/
public class DownLoadTask {
private Context context;
private FileInfo fileInfo;
private int countForThread = 3;//线程的数量
private int mFinished;
private DownLoadTaskImpl downLoadTask;
private List<ThreadInfo> threadInfos;
private List<DownLoadThread> downLoadThreads;
public boolean isPause = false;
public static ExecutorService sExecutorService = Executors.newCachedThreadPool();//共用一个线程池
public DownLoadTask(Context context,FileInfo fileInfo) {
this.fileInfo = fileInfo;
this.context = context;
downLoadTask = new DownLoadTaskImpl(context);
}
public void down(){
threadInfos = downLoadTask.getThreadInfos(fileInfo.getUrl());
if(threadInfos.size() == 0){
mFinished = 0;
//计算每个线程应下载的长度
int every_length = fileInfo.getLength()/countForThread;
for(int i = 0;i<countForThread;i++){
ThreadInfo threadInfo = new ThreadInfo();
threadInfo.setStart_flag(i*every_length);
threadInfo.setEnd_flag((i+1)*every_length-1);
threadInfo.setFinished(0);
threadInfo.setUrl(fileInfo.getUrl());
threadInfo.setThread_id(i);
//可能不能平分,最后一个线程的长度为剩余的所有
if(i == countForThread-1){
threadInfo.setEnd_flag(fileInfo.getLength());
}
downLoadTask.insertThreadInfo(threadInfo);
threadInfos.add(threadInfo);
}
}else {
//该文件一共下载了多少了
mFinished = fileInfo.getFinished();
}
downLoadThreads = new ArrayList<>();
DownLoadThread downLoadThread = null;
for(int i = 0;i<threadInfos.size();i++){
downLoadThread = new DownLoadThread(threadInfos.get(i));
// downLoadThread.start();
DownLoadTask.sExecutorService.execute(downLoadThread);//执行线程,相当于开启个线程使用这个就不需要使用.start方法
downLoadThreads.add(downLoadThread);
}
}
//真正开始下载文件的线程
class DownLoadThread extends Thread{
private ThreadInfo threadInfo;
private boolean isFinished;//该线程是否结束
public DownLoadThread(ThreadInfo threadInfo) {
this.threadInfo = threadInfo;
Log.e("------------->","threadInfo:"+threadInfo);
}
@Override
public void run() {
super.run();
HttpURLConnection connection = null;
RandomAccessFile accessFile = null;
InputStream inputStream = null;
Intent intent = new Intent();
intent.setAction("UPDATE_PROGRESSBAR");
try {
URL url = new URL(threadInfo.getUrl());
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
//下载开始的范围是,这个线程的开始下载的地方+已经下载的进度
long start = threadInfo.getStart_flag()+threadInfo.getFinished();
//设置下载的范围
connection.setRequestProperty("Range","bytes="+start+"-"+threadInfo.getEnd_flag());
File file = new File(DownLoadService.PATH,fileInfo.getFile_name());
accessFile = new RandomAccessFile(file,"rwd");
//设置文件写入位置
accessFile.seek(start);
int len = -1;
byte[] bytes = new byte[1024];
if(connection.getResponseCode() == 206){
inputStream = connection.getInputStream();
long time = System.currentTimeMillis();
while ((len = inputStream.read(bytes))!=-1){
accessFile.write(bytes,0,len);
//文件整体的下载进度
mFinished+=len;
threadInfo.setFinished(threadInfo.getFinished()+len);
//每1秒钟发送一个广播更新界面
if(System.currentTimeMillis()-time>1000){
time = System.currentTimeMillis();
//以便区分下载的是那个文件
intent.putExtra("id",fileInfo.getId());
intent.putExtra("length",fileInfo.getLength());
intent.putExtra("finished",mFinished);
context.sendBroadcast(intent);
}
//暂停更新数据库
if(isPause){
downLoadTask.updateThreadInfo(threadInfo,threadInfo.getThread_id(),threadInfo.getUrl());
return;
}
}
Log.e("------------>","线程结束:"+threadInfo.toString());
isFinished = true;
downLoadTask.updateThreadInfo(threadInfo,threadInfo.getThread_id(),threadInfo.getUrl());
checkAllThreadFinish();
}
} catch (Exception e) {
e.printStackTrace();
}finally {
connection.disconnect();
if(inputStream!=null){
try {
inputStream.close();
accessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//所有的线程下载完成
private synchronized void checkAllThreadFinish(){
boolean finishAll = true;
for(DownLoadThread downLoadThread:downLoadThreads){
if(!downLoadThread.isFinished){
finishAll = false;
return;
}
}
if(finishAll){
downLoadTask.deleteThreadInfo(fileInfo.getUrl());
//有些时候可能刚好下完,但是那1秒的时候没有取到所以进度可能停在97%,所以这样处理保证视觉的效果,可以直接将mFinished替换为fileInfo.getLength()。
Intent intent = new Intent();
intent.setAction("UPDATE_PROGRESSBAR");
intent.putExtra("id",fileInfo.getId());
intent.putExtra("length",fileInfo.getLength());
intent.putExtra("finished",mFinished);
context.sendBroadcast(intent);
}
}
}
}
3、界面的代码
上面罗列知识点的时候,说到了权限,如果手机系统是6.0 以上的要获取权限即请求用户允许的那种,否则会出现android.system.ErrnoException: open failed: EACCES (Permission denied)异常,下面代码中涉及权限的就是模拟一下,具体逻辑没有严格的去实现,大家看的时候需要注意。。
package com.example.a_0102.mylearn.download;
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.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import com.example.a_0102.mylearn.R;
import java.util.ArrayList;
import java.util.List;
/**
* 断点续传
* 一个文件可以分成几部分,使用不同的线程进行下载,使用数据库存储每个线程的下载进度
*/
public class DownLoadActivity extends AppCompatActivity {
private ListView mListView;
private List<FileInfo> fileInfoList;
private ListViewAdapter adapter;
private UpdateUIReceiver mUpdateUIReceiver;
private DownLoadTaskImpl downLoadTask;
private Button mBtnDel;
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_down_load);
//申请权限
if (ContextCompat.checkSelfPermission(DownLoadActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
//没有权限
Log.e("------------->", "没有权限");
ActivityCompat.requestPermissions(DownLoadActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
} else {
Log.e("------------->", "已经有权限");
}
mBtnDel = findViewById(R.id.btn_del);
downLoadTask = new DownLoadTaskImpl(this);
//从数据库获取要下载的文件
fileInfoList = new ArrayList<>();
fileInfoList = downLoadTask.getFileInfo();
//这里是用来模拟,具体请按照需求来写
if (fileInfoList.size() == 0) {
FileInfo fileInfo1 = new FileInfo(0, "http://oslw24znh.bkt.clouddn.com/android2017_07_05.apk", "xiaobang.apk", 0, 0, 0);
FileInfo fileInfo2 = new FileInfo(1, "http://ofmudsqae.bkt.clouddn.com/%E5%91%A8%E5%86%AC%E9%9B%A8%20-%20%E4%B8%8D%E5%AE%8C%E7%BE%8E%E5%A5%B3%E5%AD%A9.mp3", "buwanmei.mp3", 0, 0, 0);
fileInfoList.add(fileInfo1);
fileInfoList.add(fileInfo2);
}
mListView = findViewById(R.id.listview);
adapter = new ListViewAdapter();
mListView.setAdapter(adapter);
//为了测试写的,可忽略
mBtnDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("------------>","dddsize:"+downLoadTask.getFileInfo().size());
downLoadTask.deleteFileInfo();
Log.e("------------>","size:"+downLoadTask.getFileInfo().size());
downLoadTask.deleteThreadInfo();
}
});
}
//申请权限的回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
Log.e("------------->", "requestCode:" + requestCode + "," + permissions[0]);
if (requestCode == 0) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.e("------------->", "授权被允许" );
}else {
Log.e("------------->", "授权没有被允许" );
}
}
}
@Override
protected void onResume() {
super.onResume();
// 1. 实例化BroadcastReceiver子类 & IntentFilter
mUpdateUIReceiver = new UpdateUIReceiver();
IntentFilter intentFilter = new IntentFilter();
// 2. 设置接收广播的类型
intentFilter.addAction("UPDATE_PROGRESSBAR");
// 3. 动态注册:调用Context的registerReceiver()方法
registerReceiver(mUpdateUIReceiver, intentFilter);
}
// 注册广播后,要在相应位置记得销毁广播
// 即在onPause() 中unregisterReceiver(mBroadcastReceiver)
// 当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中
// 当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。
@Override
protected void onPause() {
super.onPause();
//销毁在onResume()方法中的广播
unregisterReceiver(mUpdateUIReceiver);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (intent == null) {
return;
}
stopService(intent);
}
private class ListViewAdapter extends BaseAdapter {
@Override
public int getCount() {
return fileInfoList.size();
}
@Override
public Object getItem(int position) {
return fileInfoList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = LayoutInflater.from(DownLoadActivity.this).inflate(R.layout.layout_down_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.mProgress = convertView.findViewById(R.id.progress);
viewHolder.mBtnDown = convertView.findViewById(R.id.btn_down);
viewHolder.mBtnStop = convertView.findViewById(R.id.btn_stop);
convertView.setTag(viewHolder);
//不用更新的尽量写在这里,防止每次都调用,进度设置为100
viewHolder.mProgress.setMax(100);
viewHolder.mBtnDown.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
intent = new Intent(DownLoadActivity.this, DownLoadService.class);
intent.putExtra("status", DownLoadService.STATUS_START);
intent.putExtra("fileinfo", fileInfoList.get(position));
startService(intent);
if (!downLoadTask.isExitFileInfo(fileInfoList.get(position).getId())) {
downLoadTask.insertFileInfo(fileInfoList.get(position));
}
}
});
viewHolder.mBtnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
intent = new Intent(DownLoadActivity.this, DownLoadService.class);
intent.putExtra("status", DownLoadService.STATUS_STOP);
intent.putExtra("fileinfo", fileInfoList.get(position));
startService(intent);
}
});
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
FileInfo fileInfo = fileInfoList.get(position);
viewHolder.mProgress.setProgress(fileInfo.getProgress());
return convertView;
}
class ViewHolder {
private ProgressBar mProgress;
private Button mBtnDown;
private Button mBtnStop;
}
}
/**
* 用于更新UI的广播
* 使用静态注册的广播,广播的类如果是内部类,那么,该类必须为static修饰的类,否则has no zero argument constructor 这个异常
* https://blog.csdn.net/zhongjianblackberry/article/details/56670084
* 或者用动态注册广播
*/
public class UpdateUIReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("UPDATE_PROGRESSBAR")) {
int id = intent.getIntExtra("id", 0);
int finished = intent.getIntExtra("finished", 0);
int length = intent.getIntExtra("length", 0);
if (length == 0 || length < 0) {
return;
}
int progress = finished * 100 / length;
FileInfo fileInfo = fileInfoList.get(id);
fileInfo.setFinished(finished);
fileInfo.setLength(length);
fileInfo.setProgress(progress);
adapter.notifyDataSetChanged();
downLoadTask.updateFileInfo(fileInfo, id);
}
}
}
}
4、接下来是文件类和线程类的代码
public class FileInfo implements Serializable {
private int id;
private String url;//文件的URL
private String file_name;//文件名称
private int progress;//当前进度(显示在进度条上的)
private int finished;//已下载完的(实际下载的大小)
private int length;//文件的大小
public FileInfo() {
}
public FileInfo(int id, String url, String file_name, int progress, int finished, int length) {
this.id = id;
this.url = url;
this.file_name = file_name;
this.progress = progress;
this.finished = finished;
this.length = length;
}
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 getFile_name() {
return file_name;
}
public void setFile_name(String file_name) {
this.file_name = file_name;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
this.progress = progress;
}
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 + '\'' +
", file_name='" + file_name + '\'' +
", progress=" + progress +
", finished=" + finished +
", length=" + length +
'}';
}
}
public class ThreadInfo implements Serializable {
private int id;//主键自增
private int thread_id;//如果没有id,唯一的标识,多线程的时候就不知道更新哪个了
private String url;
private long start_flag;
private long end_flag;
private long finished;//该线程的下载进度
public ThreadInfo() {
}
public ThreadInfo(int thread_id, String url, long start_flag, long end_flag, long finished) {
this.thread_id = thread_id;
this.url = url;
this.start_flag = start_flag;
this.end_flag = end_flag;
this.finished = finished;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getThread_id() {
return thread_id;
}
public void setThread_id(int thread_id) {
this.thread_id = thread_id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public long getStart_flag() {
return start_flag;
}
public void setStart_flag(long start_flag) {
this.start_flag = start_flag;
}
public long getEnd_flag() {
return end_flag;
}
public void setEnd_flag(long end_flag) {
this.end_flag = end_flag;
}
public long getFinished() {
return finished;
}
public void setFinished(long finished) {
this.finished = finished;
}
@Override
public String toString() {
return "ThreadInfo{" +
"id=" + id +
", thread_id=" + thread_id +
", url='" + url + '\'' +
", start_flag=" + start_flag +
", end_flag=" + end_flag +
", finished=" + finished +
'}';
}
}
5、数据库的代码
这里要用单例模式,否则会报错
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* 要用单例的,否则会出现Cannot perform this operation because the connection pool has been closed
*/
public class DbHalper extends SQLiteOpenHelper {
private static final String DB_NAME = "downloadfile";
private static final int DB_VERSION = 1;
private static final String CREATE_THREAD_INFO = "create table thread_info (id integer primary key autoincrement,thread_id int,url text ,start_flag int,end_flag int,finished int);";
private static final String CREATE_FILE_INFO = "create table file_info (id integer primary key,url text ,file_name text,length int,progress int,finished int);";
private static DbHalper dbHalper;
public static DbHalper getDbHalper(Context context){
if(dbHalper == null){
dbHalper = new DbHalper(context);
}
return dbHalper;
}
private DbHalper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_THREAD_INFO);
db.execSQL(CREATE_FILE_INFO);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
public interface IDownLoadTask {
/**
* 插入线程信息
*
* @param threadInfo
*/
void insertThreadInfo(ThreadInfo threadInfo);
/**
* 更新线程信息
*
* @param threadInfo
* @param id
*/
void updateThreadInfo(ThreadInfo threadInfo, int id, String url);
/**
* 删除下载完成的线程记录
*
* @param url
*/
void deleteThreadInfo(String url);
/**
* 获取所有线程信息
*
* @param url
* @return
*/
List<ThreadInfo> getThreadInfos(String url);
/**
* 获取所有线程信息
*
* @return
*/
List<ThreadInfo> getThreadInfos();
/**
* 插入文件信息
*
* @param fileInfo
*/
void insertFileInfo(FileInfo fileInfo);
/**
* 修改文件的信息
*
* @param fileInfo
* @param id
*/
void updateFileInfo(FileInfo fileInfo, int id);
/**
* 该文件信息是否存在
*
* @param id
* @return
*/
boolean isExitFileInfo(int id);
/**
* 查询文件信息
*
* @return
*/
List<FileInfo> getFileInfo();
/**
* 删除文件信息
*/
void deleteFileInfo();
/**
* 删除文件下载的线程信息
*/
void deleteThreadInfo();
}
接口类的实现,注意同步,否则多个线程一起操作一个方法会出现“惊喜“
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import java.util.ArrayList;
import java.util.List;
/**
* 增、删、改方法要保证线程安全,同一时刻只能有一个线程访问
*/
public class DownLoadTaskImpl implements IDownLoadTask {
private DbHalper dbHalper;
private SQLiteDatabase db;
public DownLoadTaskImpl(Context context) {
dbHalper = DbHalper.getDbHalper(context);
}
@Override
public synchronized void insertThreadInfo(ThreadInfo threadInfo) {
SQLiteDatabase db = dbHalper.getWritableDatabase();
db.execSQL("insert into thread_info (thread_id,url,start_flag,end_flag,finished) values (?,?,?,?,?);",
new Object[]{threadInfo.getThread_id(),threadInfo.getUrl(),threadInfo.getStart_flag(),
threadInfo.getEnd_flag(),threadInfo.getFinished()});
db.close();
}
@Override
public synchronized void updateThreadInfo(ThreadInfo threadInfo, int thread_id,String url) {
SQLiteDatabase db = dbHalper.getWritableDatabase();
db.execSQL("update thread_info set thread_id=?, url=?,start_flag=?,end_flag=?,finished=? where thread_id = ? and url = ?;",
new Object[]{threadInfo.getThread_id(),threadInfo.getUrl(), threadInfo.getStart_flag(),
threadInfo.getEnd_flag(),threadInfo.getFinished(),thread_id,url});
db.close();
}
@Override
public synchronized void deleteThreadInfo(String url) {
SQLiteDatabase db = dbHalper.getWritableDatabase();
db.execSQL("delete from thread_info where url=?;",new String[]{url});
db.close();
}
@Override
public List<ThreadInfo> getThreadInfos(String url) {
List<ThreadInfo> threadInfos = new ArrayList<>();
SQLiteDatabase db = dbHalper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from thread_info where url=?;",new String[]{url});
while (cursor.moveToNext()){
ThreadInfo threadInfo = new ThreadInfo();
threadInfo.setThread_id(cursor.getInt(cursor.getColumnIndex("thread_id")));
threadInfo.setUrl(cursor.getString(cursor.getColumnIndex("url")));
threadInfo.setStart_flag(cursor.getInt(cursor.getColumnIndex("start_flag")));
threadInfo.setEnd_flag(cursor.getInt(cursor.getColumnIndex("end_flag")));
threadInfo.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
threadInfos.add(threadInfo);
}
cursor.close();
db.close();
return threadInfos;
}
@Override
public List<ThreadInfo> getThreadInfos() {
List<ThreadInfo> threadInfos = new ArrayList<>();
SQLiteDatabase db = dbHalper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from thread_info;",new String[]{});
while (cursor.moveToNext()){
ThreadInfo threadInfo = new ThreadInfo();
threadInfo.setThread_id(cursor.getInt(cursor.getColumnIndex("thread_id")));
threadInfo.setUrl(cursor.getString(cursor.getColumnIndex("url")));
threadInfo.setStart_flag(cursor.getInt(cursor.getColumnIndex("start_flag")));
threadInfo.setEnd_flag(cursor.getInt(cursor.getColumnIndex("end_flag")));
threadInfo.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
threadInfos.add(threadInfo);
}
cursor.close();
db.close();
return threadInfos;
}
@Override
public synchronized void insertFileInfo(FileInfo fileInfo) {
SQLiteDatabase db = dbHalper.getWritableDatabase();
db.execSQL("replace into file_info (id,url,file_name,length,progress,finished) values (?,?,?,?,?,?);",
new Object[]{fileInfo.getId(),fileInfo.getUrl(),fileInfo.getFile_name(),fileInfo.getLength(),
fileInfo.getProgress(),fileInfo.getFinished()});
db.close();
}
@Override
public synchronized void updateFileInfo(FileInfo fileInfo, int id) {
SQLiteDatabase db = dbHalper.getWritableDatabase();
db.execSQL("update file_info set id=?, url=?,file_name=?,length=?,progress=?,finished=? where id = ?;",
new Object[]{fileInfo.getId(),fileInfo.getUrl(), fileInfo.getFile_name(),fileInfo.getLength(),
fileInfo.getProgress(),fileInfo.getFinished(),id});
db.close();
}
@Override
public boolean isExitFileInfo(int id) {
SQLiteDatabase db = dbHalper.getReadableDatabase();
boolean isExit = false;
Cursor cursor = db.rawQuery("select * from file_info where id=?;",new String[]{id+""});
while (cursor.moveToNext()){
isExit = true;
}
cursor.close();
db.close();
return isExit;
}
@Override
public List<FileInfo> getFileInfo() {
List<FileInfo> fileInfos = new ArrayList<>();
SQLiteDatabase db = dbHalper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from file_info;",new String[]{});
while (cursor.moveToNext()){
FileInfo fileInfo = new FileInfo();
fileInfo.setId(cursor.getInt(cursor.getColumnIndex("id")));
fileInfo.setUrl(cursor.getString(cursor.getColumnIndex("url")));
fileInfo.setFile_name(cursor.getString(cursor.getColumnIndex("file_name")));
fileInfo.setLength(cursor.getInt(cursor.getColumnIndex("length")));
fileInfo.setProgress(cursor.getInt(cursor.getColumnIndex("progress")));
fileInfo.setFinished(cursor.getInt(cursor.getColumnIndex("finished")));
fileInfos.add(fileInfo);
}
cursor.close();
db.close();
return fileInfos;
}
@Override
public synchronized void deleteFileInfo() {
SQLiteDatabase db = dbHalper.getWritableDatabase();
db.execSQL("delete from file_info;",new String[]{});
db.close();
}
@Override
public void deleteThreadInfo() {
SQLiteDatabase db = dbHalper.getWritableDatabase();
db.execSQL("delete from thread_info;",new String[]{});
db.close();
}
}
提示:可以直接使用FileDownloader一个开源的下载大文件的框架,使用就自行百度吧
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
本文标题为:Android实现多线程断点续传
基础教程推荐
- Flutter进阶之实现动画效果(三) 2022-10-28
- Android Compose自定义TextField实现自定义的输入框 2023-05-13
- iOS开发使用XML解析网络数据 2022-11-12
- iOS开发 全机型适配解决方法 2023-01-14
- iOS中如何判断当前网络环境是2G/3G/4G/5G/WiFi 2023-06-18
- IOS获取系统相册中照片的示例代码 2023-01-03
- Android实现短信验证码输入框 2023-04-29
- iOS Crash常规跟踪方法及Bugly集成运用详细介绍 2023-01-18
- MVVMLight项目Model View结构及全局视图模型注入器 2023-05-07
- Android开发Compose集成高德地图实例 2023-06-15