断点续传
来源:互联网 发布:js utf 8编码转换器 编辑:程序博客网 时间:2024/06/06 01:15
今天还是看着慕课网,把昨天的断点续传代码做了一些修改,用列表的形式,可以自定义下载一个文件需要的线程数,但是可能是由于线程的创建和销毁,还有多个线程同时操作数据库,所以感觉体验不是很好,虽然对方法声明了同步,也安排对数据库的操作在线程之外,同时也利用了线程池,来尽量减少对资源的消耗,,但是觉得不是很流畅,,,还有万恶的进度条,,,,
同样先是我的代码目录结构
adapter很简洁
List<FileInfos> list; Context mContext; LayoutInflater inflater; public MyAdapter(List<FileInfos> list, Context mContext) { this.list = list; this.mContext = mContext; inflater=LayoutInflater.from(mContext); } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View view, ViewGroup parent) { MyViewHolder holder=null; if (view==null) { view = inflater.inflate(R.layout.item_layout, parent, false); holder = new MyViewHolder(); holder.textView= (TextView) view.findViewById(R.id.textView); holder.start_bt= (Button) view.findViewById(R.id.start_bt); holder.pause_bt= (Button) view.findViewById(R.id.pause_bt); holder.progressBar= (ProgressBar) view.findViewById(R.id.progressBar); view.setTag(holder); } else { holder= (MyViewHolder) view.getTag(); } final MyViewHolder holderBuff=holder; holder.start_bt.setTag(position); holder.pause_bt.setTag(position); //设置视图中的控件 final FileInfos fileInfos = list.get(position); holder.textView.setText(fileInfos.getFileName()); holder.progressBar.setMax(100); holder.progressBar.setProgress(fileInfos.getFinished()); holderBuff.start_bt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (position==(int)holderBuff.start_bt.getTag()) { //通知service开始下载 Intent intentStart = new Intent(mContext, DownloadService.class); intentStart.setAction(DownloadService.ACTION_START); intentStart.putExtra("fileInfo",fileInfos); mContext.startService(intentStart); } } }); holderBuff.pause_bt.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (position==(int)holderBuff.pause_bt.getTag()) { //通知server暂停下载 Intent intentStop = new Intent(mContext, DownloadService.class); intentStop.setAction(DownloadService.ACTION_STOP); intentStop.putExtra("fileInfo",fileInfos); mContext.startService(intentStop); } } }); return view; } static class MyViewHolder{ TextView textView; Button start_bt,pause_bt; ProgressBar progressBar; }public class FileInfos implements Serializable{ private int id; private String url; private String fileName; private int length; private int finished;}public class ThreadInfos implements Serializable{ private int id; private String url; private int start; private int end; private int finished;}public class DBHelper extends SQLiteOpenHelper{ 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 synchronized 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 synchronized 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 synchronized void deleteThread(String url) { SQLiteDatabase db = helper.getReadableDatabase(); db.execSQL("delete from thread_info where url= ? ", new Object[]{url}); db.close(); } @Override public synchronized 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 synchronized 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 synchronized 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; //下载一个文件需要的线程个数 private int threadCount; private List<DownloadThread> downloadThreadList=new ArrayList<>(); //带缓存数量的线程池 public static ExecutorService executorService= Executors.newCachedThreadPool(); public DownloadTask(Context context, FileInfos fileInfos,int threadCount) { this.context = context; this.fileInfos = fileInfos; this.threadCount=threadCount; threadDaoImp=new ThreadDaoImp(context); } public void download() { //读取数据库的线程信息 List<ThreadInfos> list = threadDaoImp.getThreads(fileInfos.getUrl()); ThreadInfos threadInfos=null; if (list.size()==0) { //获得每个线程需要下载的长度 int length = fileInfos.getLength() / threadCount; for (int i = 0; i < threadCount; i++) { //初始化线程信息对象 threadInfos = new ThreadInfos(i,fileInfos.getUrl(),length*i,(i+1)*length-1,0); if (i==threadCount-1) { threadInfos.setEnd(fileInfos.getLength()); } list.add(threadInfos); //先数据库插入线程信息 /*if (!threadDaoImp.isExists(threadInfos.getUrl(),threadInfos.getId())) { threadDaoImp.insertThread(threadInfos); }*/ threadDaoImp.insertThread(threadInfos); } } //启动多个线程进行下载 for (int i = 0; i < list.size(); i++) { threadInfos=list.get(i); DownloadThread downloadThread = new DownloadThread(threadInfos); //downloadThread.start(); //通过线程池启动线程 executorService.execute(downloadThread); downloadThreadList.add(downloadThread); } } //判断是否所有线程都执行完毕 public synchronized void checkAllThreadsFinished() { boolean allFinished=true; for (DownloadThread downloadThread:downloadThreadList) { if (!downloadThread.isFinished) { allFinished=false; break; } } //下载完毕时,通知页面更新,并传递当前文件信息 if (allFinished) { threadDaoImp.deleteThread(fileInfos.getUrl()); Intent intent = new Intent(); intent.setAction(DownloadService.ACTION_FINISH); intent.putExtra("fileInfo",fileInfos); intent.putExtra("finish",0); context.sendBroadcast(intent); } } //下载线程 class DownloadThread extends Thread{ private ThreadInfos threadInfos; //标志是否完成 public boolean isFinished=false; public DownloadThread(ThreadInfos threadInfos) { this.threadInfos = threadInfos; } @Override public void run() { super.run(); 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; //设置每个线程的完成进度 threadInfos.setFinished(threadInfos.getFinished()+length); if (mFinished>=fileInfos.getLength()) { mFinished=fileInfos.getLength(); } if (System.currentTimeMillis()-time>1000) { time=System.currentTimeMillis(); intent.putExtra("progress",mFinished*100/fileInfos.getLength()); intent.putExtra("position",fileInfos.getId()); context.sendBroadcast(intent); } //在下载暂停时,保存下载进度 if (isPaused) { threadDaoImp.updateThread(threadInfos.getUrl(),threadInfos.getId(),threadInfos.getFinished()+length); return; } } //当前线程下载完毕 isFinished=true; //检查下载任务是否执行完毕 checkAllThreadsFinished(); //下载完成后,删除线程信息 //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(); } } } }}public interface ThreadDao { //插入线程信息 public void insertThread(ThreadInfos threadInfos); //删除线程 public void deleteThread(String url, int thredId); //删除线程 public void deleteThread(String url); //更新线程下载进度 public void updateThread(String url, int threadId, int finished); //查询线程信息 public List<ThreadInfos> getThreads(String url); //线程信息是否存在 public boolean isExists(String url, int threadId);}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_FINISH="ACTION_FINISH"; public static final String ACTION_UPDATE="ACTION_UPDATE"; public static final int MSG_INIT=0; DownloadTask downloadTask; //下载任务的集合 private Map<Integer,DownloadTask> mTasks=new LinkedHashMap<>(); 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,1); downloadTask.download(); mTasks.put(fileInfos.getId(),downloadTask); 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()); InitThread initThread = new InitThread(fileInfo); //通过线程池启动线程 DownloadTask.executorService.execute(initThread); } else if (ACTION_STOP.equals(intent.getAction())) { FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo"); Log.d("==stop====","======"+fileInfo.toString()); //从集合中取出下载任务 downloadTask=mTasks.get(fileInfo.getId()); 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 { ListView listView; List<FileInfos> list=new ArrayList<>(); MyAdapter adapter; MyBroadCastReceiver receiver; String urlKoWo="http://down.shouji.kuwo.cn/star/mobile/KuwoPlayerV3_ar_8.5.0.2_kw.apk"; String urlWangYiYun="http://wap.sogou.com/app/redir.jsp?appdown=1&u=b-5xxbPWjTJoeTuIzmwjONmoKoIYNgdlPOVy7fun_559rBQsnOOI53wn2loT2DsynmZKhKgICw9cvo3pwsuRdnnjD1ytUFis2XKdOfrva1NqaQuikpu3jJQKXph_jOiUllzWmh1shCpefgbQw2K0EZJD7JV3Lhf7&docid=-7472260854952176859&sourceid=-8776534065371990068&w=1906&stamp=20170720"; String urlQqYinYue="http://wap.sogou.com/app/redir.jsp?appdown=1&u=0Gd8piB6093-W-QPHXpNcQJvLH6U5CYdhuq4q4hqPTzLhN43WuAaT3n4Y-s0ktNHy6rGmVCuxuQ.&docid=-4411786374463855878&sourceid=-232956208690215432&w=1906&stamp=20170720"; String urlWangYiXinWen="http://wap.sogou.com/app/redir.jsp?appdown=1&u=b-5xxbPWjTJoeTuIzmwjONmoKoIYNgdlkJxIVeG_E-J5MlgzcFdg_6OaWQcQGiJV0ZeNYiLRI5ox-6Vb9Ht3p3njD1ytUFis2XKdOfrva1OAw54MZ2sYE4mD7zyni3p_HmD2WrN3oRsz6M6Y2evgE5cXC2PaxNpfD-pdxvmeHec.&docid=1984396447247278048&sourceid=4426688076946271253&w=1906&stamp=20170720"; String urlAiQiYi="http://wap.sogou.com/app/redir.jsp?appdown=1&u=0Gd8piB6093-W-QPHXpNcQJvLH6U5CYd5Zr5JWfuiTzw3lCzNhGrNbDfVRQLpRJX&docid=2339797260441192979&sourceid=7064725457117163301&w=1906&stamp=20170720"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView= (ListView) findViewById(R.id.listView); FileInfos fileInfos = new FileInfos(0, urlKoWo, "kuwo.apk", 0, 0); FileInfos fileInfos1 = new FileInfos(1, urlWangYiYun, "wangyiyun.apk", 0, 0); FileInfos fileInfos2 = new FileInfos(2, urlQqYinYue, "qq.apk", 0, 0); FileInfos fileInfos3 = new FileInfos(3, urlWangYiXinWen, "wangyixinwen.apk", 0, 0); FileInfos fileInfos4 = new FileInfos(4, urlAiQiYi, "aiqiyi.apk", 0, 0); list.add(fileInfos); list.add(fileInfos1); list.add(fileInfos2); list.add(fileInfos3); list.add(fileInfos4); adapter=new MyAdapter(list,this); listView.setAdapter(adapter); //注册广播 receiver = new MyBroadCastReceiver(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(DownloadService.ACTION_UPDATE); intentFilter.addAction(DownloadService.ACTION_FINISH); registerReceiver(receiver,intentFilter); } 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); int position = intent.getIntExtra("position", -1); if (-1!=progress) { list.get(position).setFinished(progress); adapter.notifyDataSetChanged(); } } else if (DownloadService.ACTION_FINISH.equals(intent.getAction())) { FileInfos fileInfo = (FileInfos) intent.getSerializableExtra("fileInfo"); list.get(fileInfo.getId()).setFinished(0); adapter.notifyDataSetChanged(); Toast.makeText(MainActivity.this,fileInfo.getFileName()+"下载完成",Toast.LENGTH_SHORT).show(); } } }}我这么贴代码是为了方便我自己以后用的,,如果你们感兴趣还是自己敲一遍吧,有什么其他的优化方法记得和我说一声!
阅读全文
0 0
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- 断点续传
- centos7 tesseract-ocr 安装
- Hello CSDN
- 终于有自己有博客啦
- JavaSE_Java常用类库
- Javascript进阶(三)
- 断点续传
- 前端在线编程题4
- JavaWeb中MySQL和Oracle数据库通用分页功能实现完整例子
- 给HTML5用js代码传值和拼ID的方法进行传值
- 阿里测试题
- Ubuntu 16.04下安装64位谷歌Chrome浏览器
- 【新闻】微软推出适用于Linux和Docker的SQL Server 2017版本
- c++---大小端问题
- 图片上传服务器fastDFS