2014/01-2014/03开发总结二

这一篇讲一下关于开发中遇到的具体的坑

================================================================

首先,讲一下关于渲染线程的问题,我们的项目产品要求必须效果高大上,显得牛逼华丽无比,这样才有土豪愿意付费。刚开始做动画效果,想要自己定义一个动画框架,但是问题是还有动画编辑器之类的。。。。基本上无法完成的任务。后来不得已,决定使用cocos2d-x框架,就我个人而言,我对使用这么大型的框架不太感冒,因为还有视频的东西,还有很多其他非常耗费自己的东西,觉得我们的产品性能上面不一定能撑得住,不过,就目前看来,我是想多了,移动设备的强大还是在我想象之上的。

移植完cocos2d-x框架之后,发现视频就无法播放了,还有时会引起崩溃。仔细查找了一下,发现对于opengl原来的Context而言,是与线程相关,一个线程只能有一个OpenGL的context。在网上查了一下,发现有人与我的需求是一样的,只不过很可惜,官方并没有做相应的实情,而且cocos2d-x是使用CADisplaylink做的时钟驱动,严重依赖主线程,根本无法移植,而且对于coco2d-x的修改我一直非常克制,毕竟框架的东西能不改就不改,毕竟不利于升级新版本。

在确定修改渲染线程之后,我开始干活,由于各种对apple的GCD的鼓吹,我决定使用GCD来搞定渲染线程,GCD果然强大,不到两个小时,就搞定了渲染线程的修改,非常蛋疼的是,不起作用!后来查了一下,发现有人遇到跟我一样的问题。。。。http://stackoverflow.com/questions/13972048/dispatch-sync-always-scheduling-a-block-on-main-thread。原来apple做的优化,真的让人感觉莫名其妙。

这样以来,同时为了使用runloop这个强大无比的机制,只能使用NSThread来实现了,pthread毕竟过于原始,需要自己构建大量的东西才能使用,我没有那种重复造轮子的匠人心态,更希望能做一个好产品。使用NSThread+runloop做这些实现就不用说了,是非常基础性的东西,也很快就搞定了,发现可以正常运行,跟cocos2d-x框架的运行不干扰。关于NSThread的使用,主要有两点需要提一下:

1. NSThread 的优先级问题,之前我一直认为这个是一个可有可无的参数,不是那么重要,可能是之前unix以及iOS主线程优先给我的固有印象。但是,后来测试中发现,在低性能设备中,渲染总是不及时,更改优先级为0.95之后发现表现非常流畅,本身对应用也没造成太多问题。

2. NSThread的释放问题,这个问题我一直是知道的,线程cancel的效果很差,远没有进程exit的效果给力。但是NSThread的释放还是让我困扰了一会,偶然间我决定尝试一下在这个线程自身执行cancel操作,并且给runloop加上[[NSThread currentThread] isCanceled]的判断,这样才成功释放所有资源。

关于渲染线程的修改问题就这样搞定了,顺便提一句,perforselector的时候尽量不要设置waituntidone,否则容易照成卡顿。


================================================================


接下来,是cocos2d-x动画框架的问题,我们的业务需求比较简单,很快就搞定了,application和scene而已,直接run动画就行了,由于我需要把动画文件移植到android上面,所以具体的动画播放是完全用C++写的,这下就比较尴尬了,C++如何回掉呢?最后想到时钟既然是mainthread驱动的,那也就没关系了,直接为Application设置一个bool值,通过判断这个bool值来判断动画是否执行完毕,这个方法也适用于android。这样一来,就划分了一下功能,native层面的话,需要控制动画框架资源的启动释放,以及动画文件的下载管理,同时负责调用Application中的方法来执行动画,需要启动一个timer来轮询application的是否播放动画的状态;cocos2d-x层面只负责拿到路径然后播放动画,然后释放所有的动画资源即可。iOS使用mm文件调用C++,android使用JNI调用,总体来说,实现还是比较顺利完成。


动画框架完全在预期之内完成的,但是后期在测试项目的时候,发现我们的应用在重复打开视频播放界面10次之后,会出现字幕跳动卡顿的问题。一开始我以为是播放器的问题,搜集了大量的log,不断调试参数,可一直没有解决。几乎困扰了我一个星期,发现的现象是使用dispatch_after再mainqueue中做timer的时候,发现波动很大,时间几乎比预计的时间大了一个数量级,一直不得其解。为了解决这个问题,我搜索了项目中所有会在主线程中进行执行的方法,还是没任何发现。后来,尝试不再加载动画框架,发现这个问题不存在了。最终,看了一下cocos2d-x的框架,发现应该是我们的资源释放不完全的问题。

问题来源于cocos2dx框架大量使用的单例,我对这个其实一直不太感冒,虽然我使用2.1已经改动了很多,加了很多关于单例资源释放的方法,也可能是由于这个框架是为游戏开发的原因,并未考虑到释放需要释放cocos2d-x的资源。我之前的释放方式,是delete application,然后CCDirector调用清理资源并且会退出。万万没想到的是,我忘记了CADispalylink的问题,这个并未停止,所以会再次调用CCDirector的单例,还是会创建CCDirector,所以会造成大量的资源未释放,尤其大量的CADisplaylink再主线程中,会造成整个界面都卡顿,用户体验非常差。最终改动了一下框架,添加一个方法可以取消CADisplaylink。但是另外一个问题到来,时钟驱动停止之后,发现cocos2d-x的autoreleasepool无法释放资源了,因为这个是通过CCDirector管理的。。。擦,这样就陷入了死锁状态,停止CADisplaylink无法释放CCDirector,不停止CADispalylink就会无法再次创建CCDirector。最后不得已,手工对autoreleasepool进行一次调用才可以清空所有的数据。

这里有个不得不吐的问题,有时候过度设计只会变得臃肿,带不来好处,尽量减少单例,把更多的控制权交给调用者才好,同时,求少用单例,坑太多。还有一个就是内存管理的职责是不是该与CCDirector分开啊?时钟与CCDirector的结合也太过于耦合了,感觉不是很好。


================================================================


有个不得不吐的槽,kxmoive竟然使用视频帧进行驱动的!被他误导之后,一直在这个基础之上进行修改,但无论如何修改,再遇到例如掉帧快进等问题时,用户体验实在无法忍受。最后在看别人对ffplay的研究时才发现,一直都是使用音帧作为时钟,这样才可以流畅播放,被坑死了。音帧作为时钟,将视频帧与音频帧进行同步,或者跳帧快进,或者静止等待音帧,用户体验都还不错,后来发现其他播放器也是这么解决的才释然自己没有搞错


================================================================


还有一些其他的东西,觉得没什么意义,或者我已经忘了,就不吐了,暂时写这么多吧,继续搞我的OpenGL了,好不容易有自己可以学习和写代码的时间。后面的精力,应该会转移到android和golang,mongodb上面了,短期内不会再搞这些了

你可能感兴趣的:(2014/01-2014/03开发总结二)