Problem I encountered using scheduleSelector


#1

Hi, I encountered a problem using scheduleSelector on Android that might be a bug (or more likely me misunderstanding how to use the scheduleSelector)
Basically in my scenario I have two services for downloading files, one for ftp and one for amazon S3, both are using JNI to call from C**+ code to java in order to perform the download task, then they sent notifications back to C** using a native function so that the c*+ code can know if a file is downloaded successfully or not and then continue with the application flow.
Currently the FTP part is not implemented in android but I have to keep sending empty notifications to keep the flow.
The complication starts because when I get the notifications back to the c*+ code I have to do some stuff in the UI thread (updating a label and a progress bar), in IOS I have an IOS method that makes code run on the UI thread.
But on Android I had to use scheduleSelector in order to make sure the progress bar and label are updated on the UI thread.
My problem is that when I schedule the same selector twice in a rather short time, the function inside is only executed once, I added logs inside the CCScheduler code and as I understand it, it seems that the second time the schedule arrives at CCScheduler::scheduleSelector the selector is already registered (eventhough it was supposed to be unscheduled already) and that makes my function run only once.
I hope my code will explain my situation better:

//FtpHelperWrapper
FtpWrapperNotificationObj* notificationObj = NULL;

FtpHelperWrapper::FtpHelperWrapper(std::string url, std::string story):m_sServerURL(url), m_sAppName(story){ notificationObj = new FtpWrapperNotificationObj(); }
void FtpHelperWrapper::setNotificationObjectDelegate(ttServices::FtpDelegateInterface* delegate){ TTLOGD("FtpHelperWrapper::setNotificationObjectDelegate"); notificationObj->setDelegate(delegate); }

void FtpHelperWrapper::AsyncDownloadFile(const char* path, const char* filename){ cocos2d::CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(FtpWrapperNotificationObj::notificationRecieved), notificationObj,0, false,false,0.0f); return; }

FtpHelperWrapper::~FtpHelperWrapper(){ }
//FtpWrapperNotification Objects (derrived from CCNode)

void FtpWrapperNotificationObj::setDelegate(ttServices::FtpDelegateInterface* delegate){ m_FtpDelegate = delegate; }

void FtpWrapperNotificationObj::notificationRecieved(float val) { // cocos2d::CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(FtpWrapperNotificationObj::notificationRecieved), this); (here I tried manually calling unscheduleSelector but it didn't make any difference) m_FtpDelegate->notificationRecieved(true); }

This problem looks like a weird race condition inside the CCScheduler.
Did someone ever run into similar problems or can elaborate on what I’m doing wrong here (if I’m doing something wrong)

Thanks,

Amit


#2

Hi, it seems that you got your arguments mixed up in call to scheduleSelector;
From the docs ( http://www.cocos2d-x.org/embedded/cocos2d-x/de/dee/classcocos2d_1_1_c_c_scheduler.html#a55a8137d423d8bd9d961afadf3937bfe ) :

scheduleSelector (SEL_SCHEDULE pfnSelector, CCObject *pTarget, float fInterval, unsigned int repeat, float delay, bool bPaused)

So with your call you have :
pfnSelector > ::notificationReceived
pTarget
> notificationObj (ok)
interval > 0
repeat
> false (WARNING : it will be called only once! From the docs “repeat let the action be repeated repeat + 1 times, use kCCRepeatForever to let the action run continuously”, and because false is a 0 when converted to int you effectively have 0 here);
delay > false
bPaused
> 0.0f (well this effectively is “false” as 0 value when converted to bool means false, but “false” is ok here, as you don’t want to pause it)

So the simplest solution would be to replace the value of “repeat” argument with kCCRepeatForever.
Also remember that it is better to use values from types expected as arguments (so that no automatic type conversions will be performed) so true/false for bools, numeric values for ints/floats, etc.

Hope I could help!


#3

Hi, thanks for the quick reply.
I’m intentionally calling it with repeat 0, I want to be scheduled only once.
My code is calling FtpHelperWrapper::AsyncDownloadFile a few times.
Actually the flow is like this, AsyncDownloadFile schedule the selector which called the notificationRecieved function that will eventually update the progress bar and then notify that the next file should be downloaded.
which will again call AsyncDownloadFile and so on.
So I can’t call the scheduleSelector with repeat > 0 , I just need to call it a few time according to my flow.

Thanks,
Amit