cocos2d-x中的图片异步加载机制

时间:2022-08-27 16:29:02
     3.X版本的cocos2d-x使用C++11标准,最新的C++11标准引入了对线程的原生支持,下面对其做简单介绍。在C++11标准中可以使用std::thread来快速创建一个线程:
          void threadFunc1(){
                std::cout <<  "threadFunc1:\t"  << std::endl;
                // sleep 1 秒
               std::this_thread::sleep_for(std::chrono:: seconds(1)); 
          }
          std::thread thread1(&threadFunc1);
至此我们已经创建了一个线程thread1,可以对线程进行相应的join,detach等操作。

     3.X版本的cocos2d-x使用std::thread创建的线程来进行资源的加载,cocos使用 TextureCache 来对纹理资源进行统一管理,在2.X版本中其是一个单件,用户可以直接在脚本层调用getInstance方法来获得对TextureCache的引用,而在3.X版本中,TextureCache由Director来进行管理。TextureCache提供了两个接口(这里只讨论这两个接口):
          Texture2D * addImage( const std:: string &filepath);    
           virtual void addImageAsync( const std:: string &filepath, const std:: function < void ( Texture2D *)>& callback);  
顾名思义,第一个函数提供了直接加载纹理资源的方法,查看cocos2d-x的源码发现,该方法首先在TextureCache的缓存中查找相应的纹理资源,如果未找到则直接从磁盘中读取文件,并加入到相应缓存中。而第二个函数则是其对应的异步操作方法,该方法相对复杂,下面我们来重点看该方法的实现机制。
     
     std:: function也是在C++11引入一种通用多态函数封装器( general-purpose polymorphic function wrapper 猛戳addImageAsync的最后一个参数是当纹理资源加载完成时对调用该回调函数。 下面给出资源加载的流程图,其中忽略了loadImage线程的创建及定时器的启动销毁过程:
                                    

     从流程图及源代码中可看出addImageAsync接口首先去查询缓存,如果命中则直接使用callback来处理结果,否则将要请求的资源添加到一个请求队列 _asyncStructQueue,并使用 notify_one()通知加载线程进行相应的加载操作,TextureCache使用了Lazy的方法来创建线程(线程函数loadImage),即实例化TextureCache时并不创建线程,而是等到需要异步加载时如果线程还未创建则创建一个线程。

      TextureCache ::loadImage()是TextureCache的线程函数,内部运行了一个while(true)循环,当请求队列不为空时则取出队列头进行处理,该线程使用 initWithImageFileThreadSafe来从磁盘中读取数据并创建一个texture,最后将加载好的texture放入另一个队列 _imageInfoQueue中。相反如果队列为空,则使用wait方法进行等待。

     addImageAsync方法中启动了一个定时器:
Director ::getInstance()->getScheduler()->schedule( schedule_selector ( TextureCache ::addImageAsyncCallBack), this , 0, false );, 该定时器会在每帧去检查_imageInfoQueue,如果该队列不为空,则在该帧中对_imageInfoQueue中的每个元素调用callback方法来进行渲染,当 _asyncRefCount == 0时,也即所有需要加载的纹理都已加载完成,则将该定时器清除。