本文TextureCache类异步加载功能的代码抽出,总共代码就200多行,感兴趣可以看看。
研究这个主要是因为项目中需要异步插入数据,但之前的方法在Android上总是崩溃所以想到TextureCache有异步加载的功能就将其抽出了。
原文地址:http://blog.csdn.net/qqmcy/article/details/39890837
代码下载:http://download.csdn.net/detail/qqmcy/8011589
首先,创建AsyncTaskTime类,主要模拟一个费时的方法
AsyncTaskTime.h
#include "cocos2d.h"
USING_NS_CC;
class AsyncTaskTime
{
public:
//模拟一个费时操作
bool initWithImageFileThreadSafe(const std::string &filename);
};
AsyncTaskTime.cpp
//
// AsyncTaskTime.cpp
// cpp4
//
// Created by 杜甲 on 10/8/14.
//
//
#include "AsyncTaskTime.h"
bool AsyncTaskTime::initWithImageFileThreadSafe(const std::string &filename)
{
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
return true;
}
创建异步加载功能类
AsyncTest.h
//
// AsyncTest.h
// cpp4
//
// Created by 杜甲 on 10/8/14.
//
//
#ifndef __cpp4__AsyncTest__
#define __cpp4__AsyncTest__
#include "cocos2d.h"
#include "AsyncTaskTime.h"
using namespace std;
USING_NS_CC;
class AsyncTest : public Ref
{
public:
CREATE_FUNC(AsyncTest);
virtual bool init();
AsyncTest();
// 异步加载
void addImageAsync(const string &path , const function<void(AsyncTaskTime *)> &callback);
private:
void addImageAsyncCallback(float dt);
//加载数据
void loadImage();
public:
struct AsyncStruct
{
public:
AsyncStruct(const string &fn , function<void(AsyncTaskTime *)> f): filename(fn) , callback(f){};
string filename;
function<void(AsyncTaskTime *)> callback;
};
protected:
typedef struct
{
AsyncStruct *asyncStruct;
AsyncTaskTime *image;
}ImageInfo;
thread *_loadingThread;
queue<AsyncStruct *> *_asyncStructQueue;
deque<ImageInfo *> *_ImageInfoQueue;
mutex _asyncStructQueueMutex;
mutex _imageInfoMutex;
mutex _sleepMutex;
condition_variable _sleepCondition;
bool _needQuit;
int _asyncRefCount;
unordered_map<std::string , AsyncTaskTime* > _textures;
};
#endif /* defined(__cpp4__AsyncTest__) */
AsyncTest.cpp
//
// AsyncTest.cpp
// cpp4
//
// Created by 杜甲 on 10/8/14.
//
//
#include "AsyncTest.h"
AsyncTest::AsyncTest()
: _loadingThread(nullptr)
, _asyncStructQueue(nullptr)
, _ImageInfoQueue(nullptr)
, _needQuit(false)
, _asyncRefCount(0)
{
}
bool AsyncTest::init()
{
return true;
}
void AsyncTest::addImageAsync(const string &path, const function<void (AsyncTaskTime *)> &callback)
{
AsyncTaskTime *texture = nullptr;
auto it = _textures.find(path);
if (it != _textures.end()) {
texture = it->second;
}
if (texture != nullptr) {
callback(texture);
return;
}
if (_asyncStructQueue == nullptr) {
_asyncStructQueue = new queue<AsyncStruct *>();
_ImageInfoQueue = new deque<ImageInfo *>();
_loadingThread = new thread(&AsyncTest::loadImage , this);
_needQuit = false;
}
if (0 == _asyncRefCount) {
Director::getInstance()->getScheduler()->schedule(schedule_selector(AsyncTest::addImageAsyncCallback), this, 0, false);
}
++_asyncRefCount;
auto data = new AsyncStruct(path , callback);
_asyncStructQueueMutex.lock();
_asyncStructQueue->push(data);
_asyncStructQueueMutex.unlock();
_sleepCondition.notify_one(); //将等待 condition_variable 对象的其中一个线程解除阻塞。
}
void AsyncTest::loadImage()
{
AsyncStruct *asyncStruct = nullptr;
while (true) {
queue<AsyncStruct *> *pQueue = _asyncStructQueue;
_asyncStructQueueMutex.lock();
if (pQueue->empty()) {
}
else{
asyncStruct = pQueue->front();
pQueue->pop();
_asyncStructQueueMutex.unlock();
}
AsyncTaskTime *image = nullptr;
bool generateImage = false;
auto it = _textures.find(asyncStruct->filename);
if (it == _textures.end()) {
_imageInfoMutex.lock();
ImageInfo *imageInfo;
size_t pos = 0;
size_t infoSize = _ImageInfoQueue->size();
for (; pos < infoSize; pos++) {
imageInfo = (*_ImageInfoQueue)[pos];
if (imageInfo->asyncStruct->filename.compare(asyncStruct->filename) == 0)
break;
}
_imageInfoMutex.unlock();
if (infoSize == 0 || pos == infoSize)
generateImage = true;
}
if (generateImage) {
const string &filename = asyncStruct->filename;
image = new AsyncTaskTime();
if (image && !image->initWithImageFileThreadSafe(filename)) {
continue;
}
}
auto imageInfo = new ImageInfo();
imageInfo->asyncStruct = asyncStruct;
imageInfo->image = image;
_imageInfoMutex.lock();
_ImageInfoQueue->push_back(imageInfo);
_imageInfoMutex.unlock();
}
if (_asyncStructQueue != nullptr) {
delete _asyncStructQueue;
_asyncStructQueue = nullptr;
delete _ImageInfoQueue;
_ImageInfoQueue = nullptr;
}
}
void AsyncTest::addImageAsyncCallback(float dt)
{
deque<ImageInfo *> *imagesQueue = _ImageInfoQueue;
_imageInfoMutex.lock();
if (imagesQueue->empty()) {
_imageInfoMutex.unlock();
}
else{
auto imageInfo = imagesQueue->front();
imagesQueue->pop_front();
_imageInfoMutex.unlock();
auto asyncStruct = imageInfo->asyncStruct;
auto image = imageInfo->image;
if (asyncStruct->callback) {
asyncStruct->callback(image);
}
--_asyncRefCount;
if (0 == _asyncRefCount) {
Director::getInstance()->getScheduler()->unschedule(schedule_selector(AsyncTest::addImageAsyncCallback), this);
}
}
}
调用:
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "AsyncTest.h"
USING_NS_CC;
class HelloWorld : public cocos2d::Layer
{
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
HelloWorld();
virtual bool init();
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* scene();
// implement the "static node()" method manually
CREATE_FUNC(HelloWorld);
private:
Size winSize;
//这里添加一个回调方法
void loadCallback1(AsyncTaskTime *time);
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//
// 1. super init first
if ( !Layer::init() )
{
return false;
}
auto as = AsyncTest::create();
as->retain();
as->addImageAsync("test", CC_CALLBACK_1(HelloWorld::loadCallback1, this));
return true;
}
void HelloWorld::loadCallback1(AsyncTaskTime *time)
{
log("加载完成");
}
控制台:
cocos2d: 加载完成
这样我们就将TextureCache中
virtual void addImageAsync(conststd::string &filepath, const std::function<void(Texture2D*)>& callback);
这个异步加载数据的功能实现了。