Pause JS DisplayLink if nothing to process.

Reviewed By: @jspahrsummers

Differential Revision: D2489107
This commit is contained in:
Alexey Lang 2015-09-29 05:26:01 -07:00 committed by facebook-github-bot-4
parent 4c74f01b85
commit e727fc817b
5 changed files with 76 additions and 10 deletions

View File

@ -309,6 +309,15 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
config[moduleData.name] = moduleData.config; config[moduleData.name] = moduleData.config;
if ([moduleData.instance conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) { if ([moduleData.instance conformsToProtocol:@protocol(RCTFrameUpdateObserver)]) {
[_frameUpdateObservers addObject:moduleData]; [_frameUpdateObservers addObject:moduleData];
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
__weak typeof(self) weakSelf = self;
__weak typeof(_javaScriptExecutor) weakJavaScriptExecutor = _javaScriptExecutor;
observer.pauseCallback = ^{
[weakJavaScriptExecutor executeBlockOnJavaScriptQueue:^{
[weakSelf updateJSDisplayLinkState];
}];
};
} }
} }
@ -317,6 +326,23 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
}, NULL); }, NULL);
} }
- (void)updateJSDisplayLinkState
{
RCTAssertJSThread();
BOOL pauseDisplayLink = ![_scheduledCallbacks count] && ![_scheduledCalls count];
if (pauseDisplayLink) {
for (RCTModuleData *moduleData in _frameUpdateObservers) {
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
if (!observer.paused) {
pauseDisplayLink = NO;
break;
}
}
}
_jsDisplayLink.paused = pauseDisplayLink;
}
- (void)injectJSONConfiguration:(NSString *)configJSON - (void)injectJSONConfiguration:(NSString *)configJSON
onComplete:(void (^)(NSError *))onComplete onComplete:(void (^)(NSError *))onComplete
{ {
@ -620,6 +646,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
} else { } else {
[strongSelf->_scheduledCalls addObject:call]; [strongSelf->_scheduledCalls addObject:call];
} }
[strongSelf updateJSDisplayLinkState];
RCTProfileEndEvent(0, @"objc_call", call); RCTProfileEndEvent(0, @"objc_call", call);
}]; }];
@ -804,7 +831,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink]; RCTFrameUpdate *frameUpdate = [[RCTFrameUpdate alloc] initWithDisplayLink:displayLink];
for (RCTModuleData *moduleData in _frameUpdateObservers) { for (RCTModuleData *moduleData in _frameUpdateObservers) {
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance; id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
if (![observer respondsToSelector:@selector(isPaused)] || !observer.paused) { if (!observer.paused) {
RCT_IF_DEV(NSString *name = [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp];) RCT_IF_DEV(NSString *name = [NSString stringWithFormat:@"[%@ didUpdateFrame:%f]", observer, displayLink.timestamp];)
RCTProfileBeginFlowEvent(); RCTProfileBeginFlowEvent();
@ -833,6 +860,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
[self _actuallyInvokeAndProcessModule:@"BatchedBridge" [self _actuallyInvokeAndProcessModule:@"BatchedBridge"
method:@"processBatch" method:@"processBatch"
arguments:@[[calls valueForKey:@"js_args"]]]; arguments:@[[calls valueForKey:@"js_args"]]];
[self updateJSDisplayLinkState];
} }
RCTProfileEndEvent(0, @"objc_call", nil); RCTProfileEndEvent(0, @"objc_call", nil);

View File

@ -93,18 +93,30 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
@synthesize bridge = _bridge; @synthesize bridge = _bridge;
@synthesize paused = _paused; @synthesize paused = _paused;
@synthesize pauseCallback = _pauseCallback;
RCT_EXPORT_MODULE() RCT_EXPORT_MODULE()
- (instancetype)init - (instancetype)init
{ {
if ((self = [super init])) { if ((self = [super init])) {
_paused = YES;
_eventQueue = [NSMutableDictionary new]; _eventQueue = [NSMutableDictionary new];
_eventQueueLock = [NSLock new]; _eventQueueLock = [NSLock new];
} }
return self; return self;
} }
- (void)setPaused:(BOOL)paused
{
if (_paused != paused) {
_paused = paused;
if (_pauseCallback) {
_pauseCallback();
}
}
}
- (void)sendAppEventWithName:(NSString *)name body:(id)body - (void)sendAppEventWithName:(NSString *)name body:(id)body
{ {
[_bridge enqueueJSCall:@"RCTNativeAppEventEmitter.emit" [_bridge enqueueJSCall:@"RCTNativeAppEventEmitter.emit"
@ -169,7 +181,7 @@ RCT_EXPORT_MODULE()
} }
_eventQueue[eventID] = event; _eventQueue[eventID] = event;
_paused = NO; self.paused = NO;
[_eventQueueLock unlock]; [_eventQueueLock unlock];
} }
@ -202,7 +214,7 @@ RCT_EXPORT_MODULE()
[_eventQueueLock lock]; [_eventQueueLock lock];
NSDictionary *eventQueue = _eventQueue; NSDictionary *eventQueue = _eventQueue;
_eventQueue = [NSMutableDictionary new]; _eventQueue = [NSMutableDictionary new];
_paused = YES; self.paused = YES;
[_eventQueueLock unlock]; [_eventQueueLock unlock];
for (id<RCTEvent> event in eventQueue.allValues) { for (id<RCTEvent> event in eventQueue.allValues) {

View File

@ -40,11 +40,15 @@
*/ */
- (void)didUpdateFrame:(RCTFrameUpdate *)update; - (void)didUpdateFrame:(RCTFrameUpdate *)update;
@optional
/** /**
* Synthesize and set to true to pause the calls to -[didUpdateFrame:] * Synthesize and set to true to pause the calls to -[didUpdateFrame:]
*/ */
@property (nonatomic, assign, getter=isPaused) BOOL paused; @property (nonatomic, readonly, getter=isPaused) BOOL paused;
/**
* Callback for pause/resume observer.
* Observer should call it when paused property is changed.
*/
@property (nonatomic, copy) dispatch_block_t pauseCallback;
@end @end

View File

@ -71,6 +71,7 @@
@synthesize bridge = _bridge; @synthesize bridge = _bridge;
@synthesize paused = _paused; @synthesize paused = _paused;
@synthesize pauseCallback = _pauseCallback;
RCT_EXPORT_MODULE() RCT_EXPORT_MODULE()
@ -120,7 +121,7 @@ RCT_EXPORT_MODULE()
- (void)stopTimers - (void)stopTimers
{ {
_paused = YES; self.paused = YES;
} }
- (void)startTimers - (void)startTimers
@ -129,7 +130,17 @@ RCT_EXPORT_MODULE()
return; return;
} }
_paused = NO; self.paused = NO;
}
- (void)setPaused:(BOOL)paused
{
if (_paused != paused) {
_paused = paused;
if (_pauseCallback) {
_pauseCallback();
}
}
} }
- (void)didUpdateFrame:(__unused RCTFrameUpdate *)update - (void)didUpdateFrame:(__unused RCTFrameUpdate *)update

View File

@ -269,6 +269,7 @@ NSInteger kNeverProgressed = -10000;
} }
@synthesize paused = _paused; @synthesize paused = _paused;
@synthesize pauseCallback = _pauseCallback;
- (instancetype)initWithBridge:(RCTBridge *)bridge - (instancetype)initWithBridge:(RCTBridge *)bridge
{ {
@ -321,6 +322,16 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
} }
} }
- (void)setPaused:(BOOL)paused
{
if (_paused != paused) {
_paused = paused;
if (_pauseCallback) {
_pauseCallback();
}
}
}
- (void)dealloc - (void)dealloc
{ {
_navigationController.delegate = nil; _navigationController.delegate = nil;
@ -355,14 +366,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
_dummyView.frame = (CGRect){{destination, 0}, CGSizeZero}; _dummyView.frame = (CGRect){{destination, 0}, CGSizeZero};
_currentlyTransitioningFrom = indexOfFrom; _currentlyTransitioningFrom = indexOfFrom;
_currentlyTransitioningTo = indexOfTo; _currentlyTransitioningTo = indexOfTo;
_paused = NO; self.paused = NO;
} }
completion:^(__unused id<UIViewControllerTransitionCoordinatorContext> context) { completion:^(__unused id<UIViewControllerTransitionCoordinatorContext> context) {
[weakSelf freeLock]; [weakSelf freeLock];
_currentlyTransitioningFrom = 0; _currentlyTransitioningFrom = 0;
_currentlyTransitioningTo = 0; _currentlyTransitioningTo = 0;
_dummyView.frame = CGRectZero; _dummyView.frame = CGRectZero;
_paused = YES; self.paused = YES;
// Reset the parallel position tracker // Reset the parallel position tracker
}]; }];
} }