
最近在研究视频下载到本地的问题,像爱奇艺,腾讯视频,迅雷看看等等一些视频播放器,如果在一个播放器里面视频下载到一半用户退出App之后,再次登录从头开始,那么就太可悲了,所以在做视频音频类的项目时,要实现的一个功能就是断点续传,就是将用户下载的视频或者音频等以字节流的形式存入数据库,下次用户再次下载时,将继续上次数据库的接着下载,这样用户体验就会很好,也大大节省了成本.
好了废话不多说,开始今天的正题.
一、先上效果图
二、使用GreenDao我们需要导入依赖
1.以下在项目gradle依赖中添加
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依赖中添加
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
3.既然我们要联网下载,读写权限肯定不能忘记了
<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的三个类
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; } } 四、本人使用了单例模式,所以在全局配置里初始化了数据库的 *** 作
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(); } } 五、因为我们是多线程,所以写一个保存每个线程下载信息的类
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 + "]"; } } 六、写一个用来记录的类,修改,添加和下载完清空数据库的 *** 作
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,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(); } } 七、多线程下载的实践类
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.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,urlstr); downloadInfos.add(info); } DownLoadInfo info = new DownLoadInfo(threadCount - 1,(threadCount - 1) * range,fileSize - 1,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,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,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(); } } } } } 八、再写一个接口类
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,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(); } } 九、写一下自己的布局文件
<?xml version="1.0" enCoding="utf-8"?> <relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:app="http://schemas.androID.com/apk/res-auto" xmlns:tools="http://schemas.androID.com/tools" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" tools:context="com.mtd.MainActivity"> <Progressbar androID:ID="@+ID/progressbar" androID:layout_wIDth="fill_parent" androID:layout_height="7.5dp" androID:layout_centerInParent="true" androID:layout_marginRight="8dp" androID:max="100" androID:progress="100" androID:visibility="visible" /> <TextVIEw androID:ID="@+ID/tv_Progress" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_below="@ID/progressbar" androID:layout_centerHorizontal="true" androID:layout_marginleft="23dp" androID:layout_marginStart="23dp" androID:layout_margintop="18dp" androID:text="" /> <button androID:ID="@+ID/downLoad" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_alignParentBottom="true" androID:layout_marginleft="100dp" androID:text="下载" /> <button androID:ID="@+ID/pause" androID:layout_toRightOf="@ID/downLoad" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_alignParentBottom="true" androID:layout_marginleft="48dp" androID:layout_marginStart="48dp" androID:text="暂停" /> </relativeLayout>
十、奉上自己的Java代码MainActivity类
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(); } }); } } 您可能感兴趣的文章:Eclipse NDK迁移到Android Studio的方法示例在启动栏制作android studio启动图标深踩Android Studio 缓存的坑及解决方法Android Studio 3.0 Gradle 配置变更Android Studio设置、改变字体和主题的方法使用Android studio编写一个小的jni程序Android Studio 代码导航快捷键Android Studio多工程引用同一个library项目配置的解决方法Android Studio中Run按钮是灰色的快速解决方法详解Android Studio中Git的配置及协同开发Android Studio配置内嵌JDK的方法AndroidStudio 配置 AspectJ 环境实现AOP的方法详解如何在Android Studio中添加RecyclerView-v7支持包Android Studio 一个工程打包多个不同包名的APK实例详解android studio library 模块中正确引用aar的实例讲解Android Studio中导入module的方法(简单版)Android Studio 引用外部依赖时报错的解决方法android项目从Eclipse迁移到Android studio中常见问题解决方法 总结 以上是内存溢出为你收集整理的Android Studio 下载视频到本地全部内容,希望文章能够帮你解决Android Studio 下载视频到本地所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)