Android多线程断点续传下载的实现
来源:互联网 发布:软件实施项目管理制度 编辑:程序博客网 时间:2024/05/08 17:30
Android多线程续传下载是Android应用中常见的功能。今天我们就来实现这样一个实例。实现效果如图:
结构如下图:
1)Activity向service传参数:将文件名,文件路径等传入service。
2)service 启动新的线程下载网络文件并存到本地。
3)向本地数据库写入下载的进度,以便确定下次下载的起始点。
4)broadcast 回传进度到Activity。
网络下载的关键点如下:
1)获取网络文件的长度
2)在本地创建文件,设置其长度和网络文件长度相同。
3)从上次下载的位置下载数据,同时保存进度到数据库。
4)将下载进度回传给Activity
开发过程如下:
(一)编写UI和实体类
文件类
public class FileInfo implements Serializable{ private int id; private String url; private String fileName; private int length; private int finished; }
线程类
public class ThreadInfo { private int id; private String url; private int start; private int end; private int finished; }
(二)编写service获得Activity传入的参数
public class DownloadService extends Service{ public static final String ACTION_START ="ACTION_START"; public static final String ACTION_STOP="ACTION_STOP"; @Override public int onStartCommand(Intent intent, int flags, int startId) { // 获得Activity传来的参数 if(ACTION_START.equals(intent.getAction())) { FileInfo fileInfo=(FileInfo)intent.getSerializableExtra("fileInfo"); Log.i("test ","start:"+fileInfo.toString()); }else if(ACTION_STOP.equals(intent.getAction())){ FileInfo fileInfo=(FileInfo)intent.getSerializableExtra("fileInfo"); } return super.onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; }}
(四)在Activity中设置点击传递文件参数
final FileInfo fileInfo=new FileInfo(0, "http://101.4.136.35:9999/fw1.dl.wdjcdn.com/files/third/WanDouJiaSetup_a9.exe", "王纪坤大逗比", 0, 0);
mBtStart.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { // 通过intent,传递参数给service Intent intent=new Intent(MainActivity.this,DownloadService.class); intent.setAction(DownloadService.ACTION_START); intent.putExtra("fileinfo", fileInfo); startService(intent); } });
(五)在service中创建子线程,实现文件的下载
在子线程中,连接网络,获取网络文件长度。在本地目录创建相同长度的文件。并返回本地文件。
class InitThread extends Thread{ private FileInfo mFileInfo=null; public InitThread(FileInfo mFileInfo) { this.mFileInfo=mFileInfo; } public void run(){ HttpURLConnection httpUrlConn = null; RandomAccessFile raf = null; try { //1连接网络文件 URL url=new URL(mFileInfo.getUrl()); httpUrlConn=(HttpURLConnection)url.openConnection(); httpUrlConn.setConnectTimeout(3000); httpUrlConn.setRequestMethod("GET"); int length=-1; if(httpUrlConn.getResponseCode()==HttpStatus.SC_OK) { //2获得文件长度 length=httpUrlConn.getContentLength(); } if(length<=0) { return ; }else{ //3在本地创建文件 File dir=new File(DOWNLOAD_PATH); if(!dir.exists()){ dir.mkdir(); } File file=new File(dir,mFileInfo.getFileName()); raf=new RandomAccessFile(file,"rwd"); raf.setLength(length); mFileInfo.setLength(length); mHandler.obtainMessage(MSG_INIT,mFileInfo).sendToTarget(); } //4设置本地文件长度 } catch (Exception e) { // TODO: handle exception }finally{ httpUrlConn.disconnect(); try { raf.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
(六)创建数据库的连接和数据库访问接口
在数据库中保持下载进度
数据库的字段和线程信息相对应
private static final String SQL_CREATE="create table thread_info(_id integer primary key autoincreament," + "thread_id integer,url text, start integer, end integer ,finished integer)";
定义数据库接口
public interface ThreadDAO { /* *插入线程信息 */ public void insertThread(ThreadInfo threadInfo); /* * 删除线程信息 */ public void deleteThread(String url,int thread_id); /* * 更新线程的下载进度 */ public void updateThread(String url,int thread_id,int finished); /* * 查询文件的线程信息,以集合的形式返回 */ public List<Thread> getThreads(String url); /* * 判断线程的信息是否存在 */ public boolean isExists(String url,int thread_id);}
实现数据库接口
public class ThreadDAOImpl implements ThreadDAO{ private DBhelper dbHelper; public ThreadDAOImpl(Context context){ dbHelper=new DBhelper(context); } @Override public void insertThread(ThreadInfo threadInfo) { // TODO Auto-generated method stub SQLiteDatabase db=dbHelper.getWritableDatabase(); db.execSQL("insert into thread_info(thread_id,url,start,end,finished)values(?,?,?,?,?)", new Object[]{threadInfo.getId(),threadInfo.getUrl(),threadInfo.getStart(),threadInfo.getEnd(),threadInfo.getFinished()}); db.close(); } @Override public void deleteThread(String url, int thread_id) { // TODO Auto-generated method stub SQLiteDatabase database=dbHelper.getWritableDatabase(); database.execSQL("delete from thread_info where url="+url+"and thread_id="+thread_id); database.close(); } @Override public void updateThread(String url, int thread_id, int finished) { // TODO Auto-generated method stub SQLiteDatabase db=dbHelper.getWritableDatabase(); db.execSQL("update thread_info set finished=? where url= ?and thread_id=?", new Object[]{finished,url,thread_id}); } @Override public List<ThreadInfo> getThreads(String url) { // TODO Auto-generated method stub List<ThreadInfo> list=new ArrayList<ThreadInfo>(); SQLiteDatabase db=dbHelper.getWritableDatabase(); Cursor cursor=db.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); } db.close(); return list; } @Override public boolean isExists(String url,int thread_id) { // TODO Auto-generated method stub SQLiteDatabase db=dbHelper.getWritableDatabase(); Cursor cursor=db.rawQuery("select * from thread_info where url=? and thread_id=?", new String[]{url,thread_id+""}); boolean exists=cursor.moveToNext(); cursor.close(); db.close(); return exists; }}
(七)定义下载任务类
public class DownloadTask { private Context mContext=null; private FileInfo mFileInfo=null; private ThreadDAO mDao=null; private int mFinished=0; public boolean isPaused=false; HttpURLConnection conn=null; RandomAccessFile raf=null; InputStream input=null; public DownloadTask(Context context,FileInfo fileInfo) { this.mContext=context; this.mFileInfo=fileInfo; mDao=new ThreadDAOImpl(mContext); } public void download(){ //读取数据库的线程信息 List<ThreadInfo> threadInfos= mDao.getThreads(mFileInfo.getUrl()); ThreadInfo threadInfo=null; if(threadInfos.size()==0){ //初始化县城信息对象 threadInfo=new ThreadInfo(0, mFileInfo.getUrl(), 0, mFileInfo.getLength(), 0); }else{ threadInfo=threadInfos.get(0); } new DownloadThread(threadInfo).start(); } /** * 下载线程 */ class DownloadThread extends Thread{ private ThreadInfo mThreadInfo=null; public DownloadThread(ThreadInfo mThreadInfo) { super(); this.mThreadInfo = mThreadInfo; } public void run(){ //向数据库插入线程信息 if(!mDao.isExists(mThreadInfo.getUrl(), mThreadInfo.getId())){ mDao.insertThread(mThreadInfo); } try { URL url=new URL(mThreadInfo.getUrl()); conn=(HttpURLConnection) url.openConnection(); conn.setConnectTimeout(3000); conn.setRequestMethod("GET"); //设置下载位置 int start=mThreadInfo.getStart()+mThreadInfo.getFinished(); conn.setRequestProperty("Range", "bytes="+start+"-"+mThreadInfo.getEnd()); //设置文件写入位置 File file=new File(DownloadService.DOWNLOAD_PATH, mFileInfo.getFileName()); raf=new RandomAccessFile(file, "rwd"); raf.seek(start); Intent intent=new Intent(DownloadService.ACTION_UPDATE); mFinished+=mThreadInfo.getFinished(); //开始下载 if(conn.getResponseCode()==HttpStatus.SC_OK){ //读取数据 input=conn.getInputStream(); byte[] buffer=new byte[1024*4]; int len=-1; long time=System.currentTimeMillis(); while((len=input.read(buffer))!=-1){ //写入文件 raf.write(buffer,0,len); //把下载进度发送广播给Activity mFinished+=len; if(System.currentTimeMillis()-time>500){ time=System.currentTimeMillis(); intent.putExtra("finished", mFinished*100/mFileInfo.getLength()); mContext.sendBroadcast(intent); } //在下载暂停时,保存下载进度 if(isPaused){ mDao.updateThread(mThreadInfo.getUrl(), mThreadInfo.getId(), mThreadInfo.getFinished()); return; } } //删除线程信息 mDao.deleteThread(mThreadInfo.getUrl(), mThreadInfo.getId()); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ conn.disconnect(); try { raf.close(); input.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }}
0 0
- Android多线程断点续传下载的实现
- Android多线程断点续传下载的实现
- android--http协议多线程断点续传下载的实现
- android--http协议多线程断点续传下载的实现
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- Android实现网络多线程断点续传下载
- 第九周项目三分数类中的运算符重载(续)(1)
- IP、ICMP、UDP、TCP校验和算法
- [Leetcode 96, Medium] Unique Binary Search Trees
- 并发编程笔记
- android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地
- Android多线程断点续传下载的实现
- 【数据结构】回顾二叉树
- 技术要点
- 07-图5. 旅游规划(25)
- Xcode插件
- Linux下编写简单的动态链接库
- 不用临时的变量 交换两个数的两种方法
- iOS系类教程之用instruments来检验你的app
- 黑马程序员-----基础加强-注解,类加载器