Android Studio 下载视频到本地,android studio官网

6
回复
564
查看
[复制链接]

325

主题

998

帖子

712

安币

手工艺人

发表于 2018-3-21 14:26:45 | 显示全部楼层 |阅读模式

            

        最近在研究视频下载到本地的问题,像爱奇艺,腾讯视频,迅雷看看等等一些视频播放器,如果在一个播放器里面视频下载到一半用户退出app之后,再次登录从头开始,那么就太可悲了,所以在做视频音频类的项目时,要实现的一个功能就是断点续传,就是将用户下载的视频或者音频等以字节流的形式存入数据库,下次用户再次下载时,将继续上次数据库的接着下载,这样用户体验就会很好,也大大节省了成本.

        好了废话不多说,开始今天的正题.

        一、先上效果图

        

        二、使用greendao我们需要导入依赖

        1.以下在项目gradle依赖中添加

[Java] 查看源文件 复制代码
compile 'org.greenrobot:greendao:3.2.2'//依赖 在最后一行插入
apply plugin: 'org.greenrobot.greendao' //greendao在第二行插入
greendao {//在依赖导入汇总添加一个自动添加数据库表名的配置依赖
 schemaversion 1 //数据库版本号
 daopackage 'com.example.greendaodemo.database' //设置时生成代码的目录
 targetgendir 'src/main/java' //设置daomaster、daosession、dao目录
}

        2.以下在工程gradle依赖中添加

[Java] 查看源文件 复制代码
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

        3.既然我们要联网下载,读写权限肯定不能忘记了

[Java] 查看源文件 复制代码
<uses-permission android:name="android.permission.internet"/> 
 <uses-permission android:name="android.permission.access_network_state"/> 
 <uses-permission android:name="android.permission.write_external_storage"/> 
 <uses-permission android:name="android.permission.read_external_storage"/> 
 <uses-permission android:name="com.google.android.providers.gsf.permission.read_gservices" /> 

        三、当然还要有实体类写入实体类后,build下make project一下,让他自动生成greendao的三个类

[Java] 查看源文件 复制代码
import org.greenrobot.greendao.annotation.entity; 
import org.greenrobot.greendao.annotation.id; 
import org.greenrobot.greendao.annotation.generated; 
/** 
 * author:created by zhangpengfei. 
 * email: 1271396448@qq.com 
 * data: 2018/1/18 
 */ 
@entity 
public class user { 
 @id 
 private long id; 
 private integer thread_id; 
 private integer start_pos; 
 private integer end_pos; 
 private integer compelete_size; 
 private string url; 
 @generated(hash = 2041931179) 
 public user(long id, integer thread_id, integer start_pos, integer end_pos, 
   integer compelete_size, string url) { 
  this.id = id; 
  this.thread_id = thread_id; 
  this.start_pos = start_pos; 
  this.end_pos = end_pos; 
  this.compelete_size = compelete_size; 
  this.url = url; 
 } 
 @generated(hash = 586692638) 
 public user() { 
 } 
 public long getid() { 
  return this.id; 
 } 
 public void setid(long id) { 
  this.id = id; 
 } 
 public integer getthread_id() { 
  return this.thread_id; 
 } 
 public void setthread_id(integer thread_id) { 
  this.thread_id = thread_id; 
 } 
 public integer getstart_pos() { 
  return this.start_pos; 
 } 
 public void setstart_pos(integer start_pos) { 
  this.start_pos = start_pos; 
 } 
 public integer getend_pos() { 
  return this.end_pos; 
 } 
 public void setend_pos(integer end_pos) { 
  this.end_pos = end_pos; 
 } 
 public integer getcompelete_size() { 
  return this.compelete_size; 
 } 
 public void setcompelete_size(integer compelete_size) { 
  this.compelete_size = compelete_size; 
 } 
 public string geturl() { 
  return this.url; 
 } 
 public void seturl(string url) { 
  this.url = url; 
 } 
} 

        四、本人使用了单例模式,所以在全局配置里初始化了数据库的操作

[Java] 查看源文件 复制代码
import android.app.application; 
import com.example.greendaodemo.database.daomaster; 
import com.example.greendaodemo.database.daosession; 
import com.example.greendaodemo.database.userdao; 
/** 
 * author:created by zhangpengfei. 
 * email: 1271396448@qq.com 
 * data: 2018/1/18 
 */ 
public class app extends application { 
 public static userdao userdao; 
 @override 
 public void oncreate() { 
  super.oncreate(); 
  daomaster.devopenhelper devopenhelper = new daomaster.devopenhelper(this, "zpf.db", null); 
  daomaster daomaster = new daomaster(devopenhelper.getwritabledb()); 
  daosession daosession = daomaster.newsession(); 
  userdao = daosession.getuserdao(); 
 } 
} 

        五、因为我们是多线程,所以写一个保存每个线程下载信息的类

[Java] 查看源文件 复制代码
public class downloadinfo { 
 /** 
  * 保存每个下载线程下载信息类 
  * 
  */ 
 private int threadid;// 下载器id 
 private int startpos;// 开始点 
 private int endpos;// 结束点 
 private int compeletesize;// 完成度 
 private string url;// 下载文件的url地址 
 public downloadinfo(int threadid, int startpos, int endpos, 
      int compeletesize, string url) { 
  this.threadid = threadid; 
  this.startpos = startpos; 
  this.endpos = endpos; 
  this.compeletesize = compeletesize; 
  this.url = url; 
 } 
 public downloadinfo() { 
 } 
 public string geturl() { 
  return url; 
 } 
 public void seturl(string url) { 
  this.url = url; 
 } 
 public int getthreadid() { 
  return threadid; 
 } 
 public void setthreadid(int threadid) { 
  this.threadid = threadid; 
 } 
 public int getstartpos() { 
  return startpos; 
 } 
 public void setstartpos(int startpos) { 
  this.startpos = startpos; 
 } 
 public int getendpos() { 
  return endpos; 
 } 
 public void setendpos(int endpos) { 
  this.endpos = endpos; 
 } 
 public int getcompeletesize() { 
  return compeletesize; 
 } 
 public void setcompeletesize(int compeletesize) { 
  this.compeletesize = compeletesize; 
 } 
 @override 
 public string tostring() { 
  return "downloadinfo [threadid=" + threadid + ", startpos=" + startpos 
    + ", endpos=" + endpos + ", compeletesize=" + compeletesize 
    + "]"; 
 } 
} 

        六、写一个用来记录的类,修改,添加和下载完清空数据库的操作

[Java] 查看源文件 复制代码
import android.util.log; 
import com.example.greendaodemo.database.userdao; 
import java.util.arraylist; 
import java.util.list; 
import static com.bwie.mtd.app.userdao; 
/** 
 * author:created by zhangpengfei. 
 * email: 1271396448@qq.com 
 * data: 2018/1/18 
 */ 
public class downloadsqltool { 
 /** 
  * 创建下载的具体信息 
  */ 
 public void insertinfos(list<downloadinfo> infos) { 
  for (downloadinfo info : infos) { 
   user user = new user(null, info.getthreadid(), info.getstartpos(), info.getendpos(), info.getcompeletesize(), info.geturl()); 
   userdao.insert(user); 
  } 
 } 
 /** 
  * 得到下载具体信息 
  */ 
 public list<downloadinfo> getinfos(string urlstr) { 
  list<downloadinfo> list = new arraylist<downloadinfo>(); 
  list<user> list1 = userdao.querybuilder().where(userdao.properties.url.eq(urlstr)).build().list(); 
  for (user user : list1) { 
   downloadinfo infoss = new downloadinfo( 
     user.getthread_id(), user.getstart_pos(), user.getend_pos(), 
     user.getcompelete_size(), user.geturl()); 
   log.d("main-----", infoss.tostring()); 
   list.add(infoss); 
  } 
  return list; 
 } 
 /** 
  * 更新数据库中的下载信息 
  */ 
 public void updatainfos(int threadid, int compeletesize, string urlstr) { 
  user user = userdao.querybuilder() 
    .where(userdao.properties.thread_id.eq(threadid), userdao.properties.url.eq(urlstr)).build().unique(); 
  user.setcompelete_size(compeletesize); 
  userdao.update(user); 
 } 
 /** 
  * 下载完成后删除数据库中的数据 
  */ 
 public void delete(string url) { 
  userdao.deleteall(); 
 } 
} 

        七、多线程下载的实践类

[Java] 查看源文件 复制代码
import android.content.context; 
import android.os.handler; 
import android.os.message; 
import android.util.log; 
import java.io.file; 
import java.io.inputstream; 
import java.io.randomaccessfile; 
import java.net.httpurlconnection; 
import java.net.url; 
import java.util.arraylist; 
import java.util.list; 
/** 
 * author:created by zhangpengfei. 
 * email: 1271396448@qq.com 
 * data: 2018/1/18 
 */ 
public class downloadhttptool { 
 /** 
  * 利用http协议进行多线程下载具体实践类 
  */ 
 private static final string tag = downloadhttptool.class.getsimplename(); 
 private int threadcount;//线程数量 
 private string urlstr;//url地址 
 private context mcontext; 
 private handler mhandler; 
 private list<downloadinfo> downloadinfos;//保存下载信息的类 
 private string localpath;//目录 
 private string filename;//文件名 
 private int filesize; 
 private downloadsqltool sqltool;//文件信息保存的数据库操作类 
 private enum download_state { 
  downloading, pause, ready;//利用枚举表示下载的三种状态 
 } 
 private download_state state = download_state.ready;//当前下载状态 
 private int globalcompelete = 0;//所有线程下载的总数 
 public downloadhttptool(int threadcount, string urlstring, 
       string localpath, string filename, context context, handler handler) { 
  super(); 
  this.threadcount = threadcount; 
  this.urlstr = urlstring; 
  this.localpath = localpath; 
  this.mcontext = context; 
  this.mhandler = handler; 
  this.filename = filename; 
  sqltool = new downloadsqltool(); 
 } 
 //在开始下载之前需要调用ready方法进行配置 
 public void ready() { 
  log.w(tag, "ready"); 
  globalcompelete = 0; 
  downloadinfos = sqltool.getinfos(urlstr); 
  if (downloadinfos.size() == 0) { 
   initfirst(); 
  } else { 
   file file = new file(localpath + "/" + filename); 
   if (!file.exists()) { 
    sqltool.delete(urlstr); 
    initfirst(); 
   } else { 
    filesize = downloadinfos.get(downloadinfos.size() - 1) 
      .getendpos(); 
    for (downloadinfo info : downloadinfos) { 
     globalcompelete += info.getcompeletesize(); 
    } 
    log.w(tag, "globalcompelete:::" + globalcompelete); 
   } 
  } 
 } 
 public void start() { 
  log.w(tag, "start"); 
  if (downloadinfos != null) { 
   if (state == download_state.downloading) { 
    return; 
   } 
   state = download_state.downloading; 
   for (downloadinfo info : downloadinfos) { 
    log.v(tag, "startthread"); 
    new downloadthread(info.getthreadid(), info.getstartpos(), 
      info.getendpos(), info.getcompeletesize(), 
      info.geturl()).start(); 
   } 
  } 
 } 
 public void pause() { 
  state = download_state.pause; 
 } 
 public void delete() { 
  compelete(); 
  file file = new file(localpath + "/" + filename); 
  file.delete(); 
 } 
 public void compelete() { 
  sqltool.delete(urlstr); 
 } 
 public int getfilesize() { 
  return filesize; 
 } 
 public int getcompeletesize() { 
  return globalcompelete; 
 } 
 //第一次下载初始化 
 private void initfirst() { 
  log.w(tag, "initfirst"); 
  try { 
   url url = new url(urlstr); 
   httpurlconnection connection = (httpurlconnection) url 
     .openconnection(); 
   connection.setconnecttimeout(5000); 
   connection.setrequestmethod("get"); 
   filesize = connection.getcontentlength(); 
   log.w(tag, "filesize::" + filesize); 
   file fileparent = new file(localpath); 
   if (!fileparent.exists()) { 
    fileparent.mkdir(); 
   } 
   file file = new file(fileparent, filename); 
   if (!file.exists()) { 
    file.createnewfile(); 
   } 
   // 本地访问文件 
   randomaccessfile accessfile = new randomaccessfile(file, "rwd"); 
   accessfile.setlength(filesize); 
   accessfile.close(); 
   connection.disconnect(); 
  } catch (exception e) { 
   e.printstacktrace(); 
  } 
  int range = filesize / threadcount; 
  downloadinfos = new arraylist<downloadinfo>(); 
  for (int i = 0; i < threadcount - 1; i++) { 
   downloadinfo info = new downloadinfo(i, i * range, (i + 1) * range 
     - 1, 0, urlstr); 
   downloadinfos.add(info); 
  } 
  downloadinfo info = new downloadinfo(threadcount - 1, (threadcount - 1) 
    * range, filesize - 1, 0, urlstr); 
  downloadinfos.add(info); 
  sqltool.insertinfos(downloadinfos); 
 } 
 //自定义下载线程 
 private class downloadthread extends thread { 
  private int threadid; 
  private int startpos; 
  private int endpos; 
  private int compeletesize; 
  private string urlstr; 
  private int totalthreadsize; 
  public downloadthread(int threadid, int startpos, int endpos, 
        int compeletesize, string urlstr) { 
   this.threadid = threadid; 
   this.startpos = startpos; 
   this.endpos = endpos; 
   totalthreadsize = endpos - startpos + 1; 
   this.urlstr = urlstr; 
   this.compeletesize = compeletesize; 
  } 
  @override 
  public void run() { 
   httpurlconnection connection = null; 
   randomaccessfile randomaccessfile = null; 
   inputstream is = null; 
   try { 
    randomaccessfile = new randomaccessfile(localpath + "/" 
      + filename, "rwd"); 
    randomaccessfile.seek(startpos + compeletesize); 
    url url = new url(urlstr); 
    connection = (httpurlconnection) url.openconnection(); 
    connection.setconnecttimeout(5000); 
    connection.setrequestmethod("get"); 
    connection.setrequestproperty("range", "bytes=" 
      + (startpos + compeletesize) + "-" + endpos); 
    is = connection.getinputstream(); 
    byte[] buffer = new byte[1024]; 
    int length = -1; 
    while ((length = is.read(buffer)) != -1) { 
     randomaccessfile.write(buffer, 0, length); 
     compeletesize += length; 
     message message = message.obtain(); 
     message.what = threadid; 
     message.obj = urlstr; 
     message.arg1 = length; 
     mhandler.sendmessage(message); 
     sqltool.updatainfos(threadid, compeletesize, urlstr); 
     log.w(tag, "threadid::" + threadid + " compelete::" 
       + compeletesize + " total::" + totalthreadsize); 
     if (compeletesize >= totalthreadsize) { 
      break; 
     } 
     if (state != download_state.downloading) { 
      break; 
     } 
    } 
   } catch (exception e) { 
    e.printstacktrace(); 
   } finally { 
    try { 
     if (is != null) { 
      is.close(); 
     } 
     randomaccessfile.close(); 
     connection.disconnect(); 
    } catch (exception e) { 
     e.printstacktrace(); 
    } 
   } 
  } 
 } 
} 

        八、再写一个接口类

[Java] 查看源文件 复制代码
import android.annotation.suppresslint; 
import android.content.context; 
import android.os.asynctask; 
import android.os.handler; 
import android.os.message; 
import android.util.log; 
/** 
 * author:created by zhangpengfei. 
 * email: 1271396448@qq.com 
 * data: 2018/1/18 
 */ 
public class downloadutil { 
 private downloadhttptool mdownloadhttptool; 
 private ondownloadlistener ondownloadlistener; 
 private int filesize; 
 private int downloadedsize = 0; 
 @suppresslint("handlerleak") 
 private handler mhandler = new handler() { 
  @override 
  public void handlemessage(message msg) { 
   // todo auto-generated method stub 
   super.handlemessage(msg); 
   int length = msg.arg1; 
   synchronized (this) {//加锁保证已下载的正确性 
    downloadedsize += length; 
   } 
   if (ondownloadlistener != null) { 
    ondownloadlistener.downloadprogress(downloadedsize); 
   } 
   if (downloadedsize >= filesize) { 
    mdownloadhttptool.compelete(); 
    if (ondownloadlistener != null) { 
     ondownloadlistener.downloadend(); 
    } 
   } 
  } 
 }; 
 public downloadutil(int threadcount, string filepath, string filename, 
      string urlstring, context context) { 
  mdownloadhttptool = new downloadhttptool(threadcount, urlstring, 
    filepath, filename, context, mhandler); 
 } 
 //下载之前首先异步线程调用ready方法获得文件大小信息,之后调用开始方法 
 public void start() { 
  new asynctask<void,void,void>() { 
   @override 
   protected void doinbackground(void... arg0) { 
    // todo auto-generated method stub 
    mdownloadhttptool.ready(); 
    return null; 
   } 
   @override 
   protected void onpostexecute(void result) { 
    // todo auto-generated method stub 
    super.onpostexecute(result); 
    filesize = mdownloadhttptool.getfilesize(); 
    downloadedsize = mdownloadhttptool.getcompeletesize(); 
    log.w("tag", "downloadedsize::" + downloadedsize); 
    if (ondownloadlistener != null) { 
     ondownloadlistener.downloadstart(filesize); 
    } 
    mdownloadhttptool.start(); 
   } 
  }.execute(); 
 } 
 public void pause() { 
  mdownloadhttptool.pause(); 
 } 
 public void delete(){ 
  mdownloadhttptool.delete(); 
 } 
 public void reset(){ 
  mdownloadhttptool.delete(); 
  start(); 
 } 
 public void setondownloadlistener(ondownloadlistener ondownloadlistener) { 
  this.ondownloadlistener = ondownloadlistener; 
 } 
 //下载回调接口 
 public interface ondownloadlistener { 
  public void downloadstart(int filesize); 
  public void downloadprogress(int downloadedsize);//记录当前所有线程下总和 
  public void downloadend(); 
 } 
} 

        九、写一下自己的布局文件

[Java] 查看源文件 复制代码
<

        十、奉上自己的java代码mainactivity类

[Java] 查看源文件 复制代码
import android.os.bundle; 
import android.os.environment; 
import android.support.v7.app.appcompatactivity; 
import android.util.log; 
import android.view.view; 
import android.widget.button; 
import android.widget.progressbar; 
import android.widget.textview; 
public class mainactivity extends appcompatactivity { 
 private final string videourl = "http://2449.vod.myqcloud.com/2449_22ca37a6ea9011e5acaaf51d105342e3.f20.mp4"; 
 private textview tv_progress;//进度显示 
 private progressbar progressbar;//进度条 
 private button download;//下载按钮 
 private button pause;//暂停按钮 
 private string path;//下载路径 
 private int max; 
 @override 
 protected void oncreate(bundle savedinstancestate) { 
  super.oncreate(savedinstancestate); 
  setcontentview(r.layout.activity_main); 
  tv_progress = (textview) findviewbyid(r.id.tv_progress); 
  progressbar = (progressbar) findviewbyid(r.id.progressbar); 
  download = (button) findviewbyid(r.id.download); 
  pause = (button) findviewbyid(r.id.pause); 
  path = environment.getexternalstoragedirectory().getabsolutepath() + "/local"; 
  final downloadutil downloadutil = new downloadutil(4, path, "drum.mp4", videourl, this); 
  downloadutil.setondownloadlistener(new downloadutil.ondownloadlistener() { 
   @override 
   public void downloadstart(int filesize) { 
    log.i("tag---filesize", filesize + ""); 
    max = filesize;//文件总长度 
    progressbar.setmax(filesize); 
   } 
   @override 
   public void downloadprogress(int downloadedsize) { 
    log.i("tag---downloadedsize", downloadedsize + ""); 
    progressbar.setprogress(downloadedsize); 
    tv_progress.settext((int) downloadedsize * 100 / max + "%"); 
   } 
   @override 
   public void downloadend() { 
    log.i("tag---end", "end"); 
   } 
  }); 
  /** 
   * 下载的点击事件 
   */ 
  download.setonclicklistener(new view.onclicklistener() { 
   @override 
   public void onclick(view view) { 
    downloadutil.start(); 
   } 
  }); 
  /** 
   * 暂停的点击事件 
   */ 
  pause.setonclicklistener(new view.onclicklistener() { 
   @override 
   public void onclick(view view) { 
    downloadutil.pause(); 
   } 
  }); 
 } 
} 






        

0

主题

9341

帖子

2890

安币

Android大神

Rank: 6Rank: 6

发表于 2018-3-21 15:05:39 | 显示全部楼层
不错不错,楼主辛苦了。。。

14

主题

1万

帖子

3899

安币

码皇(巴士元老)

Rank: 8Rank: 8

发表于 2018-3-21 17:06:25 | 显示全部楼层
感谢分享,安卓巴士有你更精彩:lol

0

主题

9245

帖子

2066

安币

Android大神

Rank: 6Rank: 6

发表于 2018-3-21 19:06:40 | 显示全部楼层
支持楼主,支持安卓巴士!

579

主题

1314

帖子

3260

安币

手工艺人

发表于 2018-3-21 20:45:26 | 显示全部楼层
不错不错,楼主辛苦了。。。

7

主题

9977

帖子

2331

安币

Android大神

Rank: 6Rank: 6

发表于 2018-3-21 22:08:56 | 显示全部楼层
不错不错,楼主辛苦了。。。

434

主题

1106

帖子

473

安币

手工艺人

发表于 2018-3-22 00:58:08 | 显示全部楼层
感谢大神~
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )