经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » Android » 查看文章
Android实现下载m3u8视频文件问题解决
来源:jb51  时间:2023/1/30 15:19:43  对本文有异议

效果图

简介

Aria

下载器采用开源框架Aria

github

中文文档

导入Aria

   implementation 'me.laoyuyu.aria:core:3.8.16'
    annotationProcessor 'me.laoyuyu.aria:compiler:3.8.16'
    implementation 'me.laoyuyu.aria:m3u8:3.8.16'

介绍

service在Appliaction中启动,即启动app即启动service并且service只启动一次,后序通过单例binder去调用服务

启动Service

在Application中默认启动Service

  1. private void bindService(){
  2. DownloadService.bindService(this, new ServiceConnection() {
  3. @Override
  4. public void onServiceConnected(ComponentName name, IBinder service) {
  5. }
  6. @Override
  7. public void onServiceDisconnected(ComponentName name) {
  8. downloadService = null;
  9. }
  10. });
  11. }

DownloadService

用于Aplication调用起服务

  1. public static void bindService(Context context, ServiceConnection connection){
  2. Intent intent = new Intent(context, DownloadService.class);
  3. context.bindService(intent, connection, Service.BIND_AUTO_CREATE);
  4. }

注册下载器

  1. @Override
  2. public void onCreate() {
  3. super.onCreate();
  4. Aria.download(this).register();
  5. Log.d("DownloadService","create service");
  6. }

若上次有未下载完成的视频,则恢复下载,并将binder赋给另一个单例binder,后续使用binder进行具体下载事项

  1. @Nullable
  2. @Override
  3. public IBinder onBind(Intent intent) {
  4. Log.d("DownloadService","bind service");
  5. long taskId = (long)SP.getInstance().GetData(BaseApplication.getContext(),"lastDownloadID",0L);
  6. if (taskId != 0L){
  7. List<DownloadEntity> entityList = Aria.download(this).getAllNotCompleteTask();
  8. if (entityList != null){
  9. HttpNormalTarget target = Aria.download(this).load(taskId);
  10. if (target.getTaskState() != STATE_COMPLETE){
  11. target.m3u8VodOption(DownloadBinder.getInstance().getOption());
  12. target.resume();
  13. Log.d("DownloadService","resume download");
  14. } else {
  15. HttpNormalTarget resume = Aria.download(this).load( entityList.get(0).getId());
  16. resume.m3u8VodOption(DownloadBinder.getInstance().getOption());
  17. if ((resume.getTaskState() == STATE_FAIL) || (resume.getTaskState() == STATE_OTHER)){
  18. resume.resetState();
  19. Log.d("DownloadService","resetState");
  20. }else {
  21. resume.resume();
  22. Log.d("DownloadService","resumeState");
  23. }
  24. }
  25. }
  26. }
  27. return DownloadBinder.getInstance();
  28. }

注销aria下载器和解除binder绑定

  1. @Override
  2. public boolean onUnbind(Intent intent) {
  3. Log.d("DownloadService","unbind service");
  4. return super.onUnbind(intent);
  5. }
  6. @Override
  7. public void onDestroy() {
  8. super.onDestroy();
  9. Aria.download(this).unRegister();
  10. Log.d("DownloadService","service onDestroy");
  11. }

下载回调

然后将Aria下载器的回调在进行一次中转,回调至单例binder,后面在下载就不需要binder服务,直接调用单例binder即可

  1. @Download.onNoSupportBreakPoint public void onNoSupportBreakPoint(DownloadTask task) {
  2. Log.d("DownloadService","该下载链接不支持断点");
  3. // DownloadBinder.getInstance().onTaskStart(task);
  4. }
  5. @Download.onTaskStart public void onTaskStart(DownloadTask task) {
  6. Log.d("DownloadService",task.getDownloadEntity().getFileName() +":开始下载");
  7. DownloadBinder.getInstance().onTaskStart(task);
  8. }
  9. @Download.onTaskStop public void onTaskStop(DownloadTask task) {
  10. Log.d("DownloadService",task.getDownloadEntity().getFileName() +":停止下载");
  11. DownloadBinder.getInstance().onTaskStop(task);
  12. }
  13. @Download.onTaskCancel public void onTaskCancel(DownloadTask task) {
  14. Log.d("DownloadService",task.getDownloadEntity().getFileName() +":取消下载");
  15. DownloadBinder.getInstance().onTaskCancel(task);
  16. }
  17. @Download.onTaskFail public void onTaskFail(DownloadTask task) {
  18. Log.d("DownloadService",task.getDownloadEntity().getFileName() +":下载失败");
  19. DownloadBinder.getInstance().onTaskFail(task);
  20. }
  21. @Download.onTaskComplete public void onTaskComplete(DownloadTask task) {
  22. Log.d("DownloadService",task.getDownloadEntity().getFileName() +":下载完成");
  23. DownloadBinder.getInstance().onTaskComplete(task);
  24. }
  25. /**
  26. * @param e 异常信息
  27. */
  28. @Download.onTaskFail void taskFail(DownloadTask task, Exception e) {
  29. try {
  30. DownloadBinder.getInstance().taskFail(task,e);
  31. ALog.d("DownloadService", task.getDownloadEntity().getFileName() +"error:"+ALog.getExceptionString(e));
  32. }catch (Exception ee){
  33. ee.printStackTrace();
  34. }
  35. }
  36. @Download.onTaskRunning public void onTaskRunning(DownloadTask task) {
  37. Log.d("DownloadService","pre = "+task.getPercent()+" "+"speed = "+ task.getConvertSpeed());
  38. DownloadBinder.getInstance().onTaskRunning(task);
  39. }
  40. }

回调接口

将服务中的Aria回调,回调至单例binder中

  1. public interface ServiceCallback {
  2. void onTaskStart(DownloadTask task);
  3. void onTaskStop(DownloadTask task);
  4. void onTaskCancel(DownloadTask task);
  5. void onTaskFail(DownloadTask task);
  6. void onTaskComplete(DownloadTask task);
  7. void onTaskRunning(DownloadTask task);
  8. void taskFail(DownloadTask task, Exception e);
  9. }

单例Binder

构造单例

  1. public class DownloadBinder extends Binder implements ServiceCallback {
  2. private static DownloadBinder binder;
  3. private DownloadBinder() {
  4. }
  5. public static DownloadBinder getInstance() {
  6. if (binder == null) {
  7. binder = new DownloadBinder();
  8. downloadReceiver = Aria.download(BaseApplication.getContext());
  9. }
  10. return binder;
  11. }

下载

将下载信息传入,并以视频type+id+name等构件下载文件夹名称,确保唯一性,然后通过配置Aria Option,使其切换至m3u8文件下载模式,具体配置文件还可配置下载速度、最大下载文件数量、线程数等等。

Aria自带数据库,可通过其数据库保存一些数据,但读取数据较慢

  1. public void startDownload(DownloadBean downloadBean) {
  2. if (downloadBean == null) return;
  3. String locationDir = FileUtils.getInstance().mainCatalogue();
  4. String name = downloadBean.getVideoType()+downloadBean.gettId() + downloadBean.getsId() + downloadBean.geteId();
  5. String subFile = FileUtils.getInstance().createFile(locationDir, name);
  6. String path = subFile + File.separator + name + ".m3u8";
  7. Log.d("DownloadService", "start download");
  8. boolean isExist = IsExist(path);
  9. if (isExist) {
  10. Log.d("DownloadService", "exist same item");
  11. if (repeatTaskId != 0) {
  12. if (Aria.download(this).load(repeatTaskId).getTaskState() != STATE_RUNNING) {
  13. if (downloadReceiver.load(repeatTaskId).getEntity().getRealUrl().equals(downloadBean.getVideoUrl())) {
  14. downloadReceiver.load(repeatTaskId).m3u8VodOption(DownloadBinder.getInstance().getOption());
  15. downloadReceiver.load(repeatTaskId).resume();
  16. } else {
  17. downloadReceiver.load(repeatTaskId).m3u8VodOption(DownloadBinder.getInstance().getOption());
  18. downloadReceiver.load(repeatTaskId).updateUrl(downloadBean.getVideoUrl()).resume();
  19. }
  20. }
  21. Log.d("DownloadService", "resume exist same item");
  22. return;
  23. }
  24. }
  25. HttpBuilderTarget target = downloadReceiver.load(downloadBean.getVideoUrl())
  26. .setFilePath(path)
  27. .ignoreFilePathOccupy()
  28. .m3u8VodOption(getOption());
  29. List<DownloadEntity> downloadEntityList = downloadReceiver.getDRunningTask();
  30. if (downloadEntityList == null) {
  31. repeatTaskId = target.create();
  32. } else {
  33. repeatTaskId = target.add();
  34. }
  35. try {
  36. repeatTaskId = target.getEntity().getId();
  37. downloadBean.setTaskId(repeatTaskId);
  38. SP.getInstance().PutData(BaseApplication.getContext(),"lastDownloadID",repeatTaskId);
  39. target.setExtendField(new Gson().toJson(downloadBean)).getEntity().save();
  40. }catch (NullPointerException e){
  41. e.printStackTrace();
  42. }
  43. }

辐射

再一次将service回调的接口回调至binder的接口,通过EventBus辐射至外部,通过一层层封装,在外部监听当前文件下载状态,只需通过监听EventBus事件即可

  1. /**
  2. * download status
  3. * 0:prepare
  4. * 1:starting
  5. * 2:pause
  6. * 3:cancel
  7. * 4:failed
  8. * 5:completed
  9. * 6:running
  10. * 7:exception*/
  11. @Override
  12. public void onTaskStart(DownloadTask task) {
  13. EventBus.getDefault().postSticky(new DownloadStatusBean(1,task.getDownloadEntity().getId(), task.getConvertSpeed(), task.getPercent(),task.getConvertFileSize(),task.getFilePath()));
  14. }
  15. @Override
  16. public void onTaskStop(DownloadTask task) {
  17. EventBus.getDefault().postSticky(new DownloadStatusBean(2,task.getDownloadEntity().getId(), task.getConvertSpeed(), task.getPercent(),task.getConvertFileSize(),task.getFilePath()));
  18. }
  19. @Override
  20. public void onTaskCancel(DownloadTask task) {
  21. EventBus.getDefault().postSticky(new DownloadStatusBean(3,task.getDownloadEntity().getId(), task.getConvertSpeed(), task.getPercent(),task.getConvertFileSize(),task.getFilePath()));
  22. }
  23. @Override
  24. public void onTaskFail(DownloadTask task) {
  25. EventBus.getDefault().postSticky(new DownloadStatusBean(4,task.getDownloadEntity().getId(), task.getConvertSpeed(), task.getPercent(),task.getConvertFileSize(),task.getFilePath()));
  26. }
  27. @Override
  28. public void onTaskComplete(DownloadTask task) {
  29. EventBus.getDefault().postSticky(new DownloadStatusBean(5,task.getDownloadEntity().getId(), task.getConvertSpeed(), task.getPercent(),task.getConvertFileSize(),task.getFilePath()));
  30. }
  31. @Override
  32. public void onTaskRunning(DownloadTask task) {
  33. EventBus.getDefault().postSticky(new DownloadStatusBean(6,task.getDownloadEntity().getId(), task.getConvertSpeed(), task.getPercent(),task.getConvertFileSize(),task.getFilePath()));
  34. }
  35. @Override
  36. public void taskFail(DownloadTask task, Exception e) {
  37. try {
  38. EventBus.getDefault().postSticky(new DownloadStatusBean(4,task.getDownloadEntity().getId(), task.getConvertSpeed(), task.getPercent(),task.getConvertFileSize(),task.getFilePath()));
  39. }catch (NullPointerException ee){
  40. ee.printStackTrace();
  41. }
  42. }
  43. }

创建下载实例

一句话我们就可以实现视频下载,然后后天服务自动回调给binder,然后binder回调给EventBus

  1. DownloadBean bean = new DownloadBean(0L,m_id,"","",sourceBean.getLink(),detailBean.getCover(),detailBean.getTitle(),"","","movie","",0);
  2. DownloadBinder.getInstance().startDownload(bean);

监听下载状态

然后只需要在需要更新界面的地方注册EventBus即可,通过封装,不同的类做不同的事情,将数据处理和UI更新进行隔离,可以提高代码阅读和执行效率

  1. /**
  2. * download status
  3. * 0:prepare
  4. * 1:starting
  5. * 2:pause
  6. * 3:cancel
  7. * 4:failed
  8. * 5:completed
  9. * 6:running
  10. * 7:exception*/
  11. /**
  12. * 下载item状态监听*/
  13. @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
  14. public void OnEvent(DownloadStatusBean bean) {
  15. taskID = bean.getTaskID();
  16. switch (bean.getStatus()) {
  17. case 1:
  18. getRunningItem();
  19. Log.d("DownloadService", "status start");
  20. break;
  21. case 2:
  22. updateStatus(bean);
  23. Log.d("DownloadService", "status pause");
  24. break;
  25. case 3:
  26. if ((index == -1) && (beanList.size() > 0)){
  27. index = 0;
  28. }
  29. Log.d("DownloadService", "status cancel"+bean.getTaskID());
  30. break;
  31. case 4:
  32. //update url
  33. failCount++;
  34. if (failCount >= 3){
  35. failedReconnect(bean);
  36. failCount = 0;
  37. isRunning = true;
  38. Log.d("DownloadService", "status fail in");
  39. }
  40. Log.d("DownloadService", "status fail");
  41. break;
  42. case 5:
  43. removeDownloadBead(bean.getTaskID());
  44. startDownload();
  45. Log.d("DownloadService", "status complete");
  46. break;
  47. case 6:
  48. if (isRunning) {
  49. getRunningItem();
  50. }
  51. updateCurItem(bean);
  52. Log.d("DownloadService", "status running: "+index);
  53. break;
  54. }
  55. }

到此这篇关于Android实现下载m3u8视频文件问题解决的文章就介绍到这了,更多相关Android下载m3u8视频内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号