Android多线程断点续传
hello_1s 人气:0多线程下载涉及到的知识点:
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一个开源的下载大文件的框架,使用就自行百度吧
加载全部内容