这一阵主要做了一下视频功能。tableView播放视频在线播放视频,以及对性能的优化。由于之前只是简单的搭了一下框架,随意扔了两个视频进工程,这几天细致地做了一下,只用到了afn框架,因为以前没做过这类的功能,所以没用SD框架,想用自己的代码实现一下。
首先为了不让视频界面很low,花了一两天的时间,利用charles抓取其他app的资源,终于是抓到了可以返回视频json文件的url。怀着激动的心情开始制作。
一、
1.拿到了可以返回视频信息资源json文件的url,首先就是先将json文件下载下来,然后再对数据进行解析。这里我是使用的afn框架,NSURLSessionDownloadTask来执行的下载任务。代码如下图
2.思路首先是将json文件下载到本地,之后就是解析json文件,文件中有视频资源url,视频标题,播放量,占位图url等好多信息。利用NSJSONSerialization就可以很轻松的将json文件转化为数组或者字典。如图,我这里是转化为字典,然后将字典逐一存入数组中。
因为是抓来的json资源,所以解析的时候一定要弄清楚json文件的结构层次,然后再判断用数组还是字典来接收数据。[]是数组 {}是字典。
解析拿到数据之后,就可以开始根据数据来制作视频播放啦。
3.首先是设置组数、行数,我设置的是一组,行数是根据解析拿到数据的数组中,元素的个数来动态确定的。方便之后的刷新,上拉加载功能,可以动态更改行数。因为拿到的一个json文件中只有10个视频的资源,所以我的加载方式就是,初始行数十,每次拉到底后再继续加载十个视频。
关于cell当然是要自定义了,因为要播放视频,还要显示标题之类的数据。自定义cell就不在这里总结了,搞好布局就好了。重点就是加载视频的问题了,因为是第一次,感觉还是很麻烦的,整体做过一次之后,就有了明确的思路。
4.重头戏就在cellForRowAtIndexPath方法中了,注意,视频播放一定要利用cell的重用机制。开写!
刚开始写的时候,就是简单的从数组中取出模型,然后给cell上的player赋上url;然后简单的处理了一下播放逻辑。感觉还不错。但是当我开始使用MJRefresh框架制作上拉、下拉刷新加载功能的时候就出大问题了。
初始数据只有十条,很少的数据下是看不出什么的。当加载到20-30个视频的时候,我发现简直是卡死了!!!界面掉帧极其严重,甚至会卡死。琢磨了下,我当前的思路是,每当一个cell要出现在视野中的时候,就给他添加一个播放器,初始化播放器的时候,将视频的url赋上去。所以就导致,每次cell要出现的时候,都要先下载视频,下载好了cell才会滚到视野,下一个cell又是这样,界面总是会卡住四五秒,视频下载完才会再滚一下。
解决方法:界面卡顿就是因为下载任务阻塞了主线程,所以要开子线程,在子线程中进行下载任务。然后等待下载任务完成,刷新一下UI界面就可以了。(还是太天真了)
之后发现即使多线程下载了,界面依旧是超级卡,因为每次上下滚动cell的时候都要开线程进行下载任务,滚的越多越快,下载任务越重,还是会越来越卡。
主要原因:1.没有做图片缓存的原因。滚动cell会一直从网络上获取图片。 2.下载任务重复,来回滚动的时候,一个cell 滚到视野-》划出视野-〉重新进入视野,即便是一个cell,出现在视野中两次,也要执行两次同样的下载任务。任务繁重。
于是开始使用缓存机制!三级缓存,缓存,本地,网络。将下载过的数据存储到缓存中,写到本地文件中,当再次滑到的时候,就直接从本地加载或者读取缓存,cpu的负担会小很多。如下图
首先先创建以下三个引用,由于网络请求数据,要考虑到网络问题,于是在视频数据没下载加载完时,在播放器上方先显示占位图片。
operationDict用于装载NSOperation,当有下载任务时,就将有下载任务的operation以键值的方式存入字典中,当下载完成时,再将其从字典中移除,我这里用的展位图片的url作为键,operation作为值存入。这样还有一个好处就是,我们可以通过键的对比,过滤掉重复的下载任务,因为下载任务的url是唯一的,当有下载任务的时候,先判断字典中有没有相同的,有就不执行下载任务,没有就添加进去,开始下载。
imageCache就是图片缓存,将下载好的占位图,以键值存入数组,再次使用的时候读取缓存就好了,道理一样,没有的就存进字典,有的就不存。
三级缓存思路就是,1.当滑动到cell时,根据cell的indexPath拿到模型中保存的url,然后根据url去本地缓存(上面介绍的字典)查找,有数据的话就直接使用;2.没有的话,再去本地文件中查找;有的话就使用,3.没有的话再根据url去网上获取下载。
下载下来之后,先根据键值判断缓存、本地中有没有该数据,有的话就不存,如果没有的话就存入缓存,写入本地沙盒,以后就不用下载了。节省了大量cpu资源,也为用户节省了大量的流量。具体实现看代码:
完成了这些操作,本以为大功告成,但是真机运行一下,发现是比之前好了很多,但是依旧是卡,掉帧随着数据量的增多越来越严重。
一轮思考时候,我发现既然有了占位图,那么干脆直接就不要给出现在视野的cell添加视频播放器,不给他视频url,当用户点击视频的播放按钮的时候,再动态的为那一行cell添加视频播放器,加载url,这不就相当于每个cell刚开始的时候就仅仅加载一个本地的占位图吗!!!佩服自己!!!(肯定有人早就知道了,但是我就是想得瑟下),当用户不想看这行cell的视频,将它滚出视野之外的时候,我们再将cell的播放器释放掉,只在用户点击播放的时候继续创建加载。免去了滑动cell时的大量加载,再也不卡顿,丝滑流畅。