6-performFunctionInCocosThread
2019-02-20 本文已影响15人
porridgechen890
问题的提出
假设现在有这样一个需求:按住一个按钮后开始录音,录音开始后播放录音动画,松开按钮后停止录音,并移除录音动画。
分析
录音由安卓和iOS的代码实现,不在cocos这一层,并且属于新开的线程。但播放动画和停止动画由cocos的代码实现,属于cocos的UI线程。所以如果安卓(或iOS)代码启动录音成功需要告诉cocos的UI线程播放动画。如果安卓(或iOS)代码停止录音成功需要告诉cocos的UI线程停止动画。在cocos里新开辟一个线程可以用std::thread,在其他线程里回调cocos的函数可以用performFunctionInCocosThread。
Android里面有runOnUiThread,IOS下有performSelectorOnMainThread。
cocos2dx 3.0系列中新加入了一个专门处理线程安全的函数performFunctionInCocosThread(),它的声明如下:
/** Calls a function on the cocos2d thread. Useful when you need to call a cocos2d function from another thread.
This function is thread safe.
@param function The function to be run in cocos2d thread.
@since v3.0
@js NA
*/
void performFunctionInCocosThread(std::function<void()> function);
代码
这个Demo展示的是如何开辟新的线程和在支线程里如何影响UI线程。
//HelloWorld.h
class HelloWorld : public cocos2d::Scene
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
void menuCloseCallback(cocos2d::Ref* pSender);
CREATE_FUNC(HelloWorld);
void threadA();
};
//HelloWorld.cpp
bool HelloWorld::init()
{
//其他未改动的代码省略了
this->addChild(sprite, 0, "helloworld");//这里给这个图加了个名字
}
void threadB()
{
Director::getInstance()->getScheduler()->performFunctionInCocosThread([]{
auto sprite = Sprite::create("res/MagentaSquare.png");
Director::getInstance()->getRunningScene()->addChild(sprite);
Size size = Director::getInstance()->getWinSize();
sprite->setPosition(Vec2(size.width/2-10, size.height/2));
});
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
std::thread t1(&HelloWorld::threadA, this);
t1.detach();
log("新开线程释放了");
//这个t2只是为了说明新开的线程的函数可以不是成员函数,普通函数也可以
std::thread t2(threadB);
t2.detach();
}
void HelloWorld::threadA()
{
Director::getInstance()->getScheduler()->performFunctionInCocosThread([this]{
//新开线程回调主线程做两件事,创建并显示一个黄色方块,隐藏原来的HelloWorld图片。
auto sprite = Sprite::create("res/YellowSquare.png");
this->addChild(sprite);
Size size = Director::getInstance()->getWinSize();
sprite->setPosition(Vec2(size.width/2+10, size.height/2));
auto spriteHelloWorld = this->getChildByName("helloworld");
if (spriteHelloWorld)
{
spriteHelloWorld->setVisible(false);
}
log("新开线程的回调执行完了");
});
log("新开线程的函数执行完了");
}
没有点按钮时.png
点了按钮之后.png
image.png