整理下最近项目做过的关于下载音视频的思路,只说思路,不会上具体代码。
我们从粗到细,慢慢道来。(本人菜鸟一枚,我这里只是说下自己的思路,有大神看见了此文章,如果有更好的解决方案,欢迎留言指正, 只是起抛砖引玉,大家一起进步。)
首先说一下大环境,Android和IOS对于视频的支持。
Android和IOS支持的视频来说,Android本身支持最强的可能是mp4,然后就是3gp,或者有的主打影音的手机会支持硬解rm/rmvb,总的来说不是很统一的(没有做过调查,轻喷)。而IOS这方面则统一的多,一般都是m3u8格式的,现在主流视频网站一般会检测你是Android还是IOS,然后返回不同的视频格式。对于文中提到的一些名词,下面有简单介绍地址的传送门。
UA(User-Agent)--
http://blog.sina.com.cn/s/blog_6a528c550102uwvx.html
这里还得提一句Android在m3u8方面的支持,Android在4.0之前是不支持m3u8这个东西的,据说在4.0上是支持了,但是一句不怎么样,有的能播有的不能播,反正就是不能用,不知道Google的家伙们怎么想的,要支持就好好支持,放出来一个半成品算是怎么回事,不能为广大的Android程序猿谋个福利么。就为了和苹果斗气么。
粗略来讲,关于下载,简单的很,无非是得到文件的源地址,得到文件流,然后再本地SD卡或者机身内存创建一个空File,然后把流中的内容放到文件中。但实际做起来,实在是麻烦+头疼的东西。
我的思路,我们需要以下几个基本的类:
1、一个界面来展示进度--activity/fragment(如果需求需要,notification也是需要的)--activity
2、一个在后台跑着的,实际上起管理这些下载任务的service--downloadService
3、一个下载Thread,实际上下载内容的线程类--downloadTask
4、SQLite数据库
下面我简单的分个类,如果说一个下载Thread就是一个下载任务的话,那我就把一个下载任务中承担多段视频的下载和单个视频的下载分别列为两类,这里有人可能会说,什么情况下会在一个下载下载thread中下载多段视频,是在下载m3u8的时候,那这时候有人又说了,为什么不开启多个下载Thread去下载多段的视频呢,我是这么考虑的,因为一个m3u8文件中有成百上千段.ts文件(这真不是夸大,我曾经下载过一段视频,一个小时多吧,切了1300多段,还是那个评论,巧(sang)夺(xin)天(bing)工(kuang)),出于这样的考虑,需要在一个下载Thread中这样下载一个m3u8,多段.ts(我当时是这么实现的,但是后来一想,可以用多线程的方法,类似于断点续传的方式,给多个线程分发下载的范围,貌似也是走的通的,不知道有没有做过的大神)。
那我们就分开来细说,先说下载多段视频的,经验之谈,先实现比较复杂的情况,再去实现简单的情况,因为一般来说简单的都可以复用复杂的逻辑,反过来却不行。
一、多段视频的下载--也就是下载m3u8:
(1)DownloadTask是具体下载任务的Thread,这里面需要有以下这几个功能:
1、下载单个文件,下载多个文件
2、解析m3u8并保存m3u8,原理就是替换m3u8文件中的内容,也就是说创建一个假的m3u8文件,格式要对,文件的地址需要换成你的视频文件在你SD卡上的存储地址。
3、广播--包括通知界面进度更改/下载开始/下载结束/下载暂停,也就是通知展示界面现在下载任务到了什么进度了。(没有想到更好的方法,或许可以用回调的方式实现,但是可能不是很好实现,就没有用这样的方式)
4、更新数据库,开始、暂停、完成的时候都要将状态/完成百分比/字节数等等等等写入到数据库中
需要注意的:下载文件的时候需要考虑很多,IOException/网络异常等等都需要做处理,然后给用户相应的提示;还有,Thread是不好控制的,怎么控制好Thread的生命周期也是一个麻烦事儿。
(2)实际上起管理作用的downloadService
1、处理从每个界面过来的逻辑,比如:
1.1、展示下载界面过来的--action包括暂停、等待、开始下载等动作,要控制好这些个不同种类的动作也是挺繁琐的事情。这里没有科技含量,但是要细心的处理好边边角角。
1.2、点开始下载的时候,也就是刚开始下载的时候过来的。
1.3、等等等等。。。看自己应用的逻辑了
2、保持一个含有正在下载、等待下载的list,用这个list来实际控制到底哪个任务需要下载,哪几个任务需要等待其他的任务下载完之后再下载。
3、保持对downloadTask的控制
实际上这个类是最复杂的,自己做下载时候时间最多的就是花在了这儿。倒不是多难,主要是因为逻辑复杂,而且还要考虑各种情况,实在是费心神
(3)展示的activity/fragment,这个没什么好说的,有广播接受者来控制界面就好了,无非是起一个会展示的作用。
这里用了广播接收者,来接受downloadTask过来的进度变化/暂停/开始的广播
还要注意的是删除文件盒数据库内容时候的配合,这里还要细心。
(4)SQLite数据库,当然了,怎么存储下载下来的文件的信息呢,还是要用数据库存下来
数据库注意的就是记得关cursor,能少调用就少调用。
然后,总的来说下载还是很麻烦的。实际上已经上线的包括很多有名的app都是同时只能下载一个视频(当然不能跟迅雷快播之类的专业做下载的比了),其他的都在等待状态,可能还是考虑到其实也是没有这个必要,下载完一个就能看,如果多个都在下载的话就不能在最短的时间内观看下载的视频了。
(作者原创,转载请贴链接)