Make sure UIImplementation methods that touch native View has the Views created
Summary: UIImplementation has a few methods that in the end touch native Views, such as dispatchViewManagerCommand, addAnimation, sendAccessibilityEvent etc. There are 2 cases where it is possible to have those methods called on shadow nodes that don't have backing Views created: - backing view is scheduled to be created but not commited yet (StateBuilder accumulates createView commands into a queue and flushes it in the very end) - shadow node doesn't mount to a View so there is no backing View Touching View in UI thread in these 2 cases will either lead to silent error (e.g. failure callback will execute), or a native crash. This diff is overriding all UIImplementation methods that touch Views in UI thread and makes sure that backing View is created before we do so. Reviewed By: ahmedre Differential Revision: D3046392
This commit is contained in:
parent
68580fcab6
commit
f4690ef8de
|
@ -169,6 +169,7 @@ public class FlatUIImplementation extends UIImplementation {
|
|||
public void measure(int reactTag, Callback callback) {
|
||||
FlatShadowNode node = (FlatShadowNode) resolveShadowNode(reactTag);
|
||||
if (node.mountsToView()) {
|
||||
mStateBuilder.ensureBackingViewIsCreated(node);
|
||||
super.measure(reactTag, callback);
|
||||
return;
|
||||
}
|
||||
|
@ -182,6 +183,7 @@ public class FlatUIImplementation extends UIImplementation {
|
|||
while (true) {
|
||||
node = Assertions.assumeNotNull((FlatShadowNode) node.getParent());
|
||||
if (node.mountsToView()) {
|
||||
mStateBuilder.ensureBackingViewIsCreated(node);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -202,6 +204,48 @@ public class FlatUIImplementation extends UIImplementation {
|
|||
callback);
|
||||
}
|
||||
|
||||
private void ensureMountsToViewAndBackingViewIsCreated(int reactTag) {
|
||||
FlatShadowNode node = (FlatShadowNode) resolveShadowNode(reactTag);
|
||||
node.forceMountToView();
|
||||
mStateBuilder.ensureBackingViewIsCreated(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void findSubviewIn(int reactTag, float targetX, float targetY, Callback callback) {
|
||||
ensureMountsToViewAndBackingViewIsCreated(reactTag);
|
||||
super.findSubviewIn(reactTag, targetX, targetY, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void measureInWindow(int reactTag, Callback callback) {
|
||||
ensureMountsToViewAndBackingViewIsCreated(reactTag);
|
||||
super.measureInWindow(reactTag, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAnimation(int reactTag, int animationID, Callback onSuccess) {
|
||||
ensureMountsToViewAndBackingViewIsCreated(reactTag);
|
||||
super.addAnimation(reactTag, animationID, onSuccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchViewManagerCommand(int reactTag, int commandId, ReadableArray commandArgs) {
|
||||
ensureMountsToViewAndBackingViewIsCreated(reactTag);
|
||||
super.dispatchViewManagerCommand(reactTag, commandId, commandArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPopupMenu(int reactTag, ReadableArray items, Callback error, Callback success) {
|
||||
ensureMountsToViewAndBackingViewIsCreated(reactTag);
|
||||
super.showPopupMenu(reactTag, items, error, success);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAccessibilityEvent(int reactTag, int eventType) {
|
||||
ensureMountsToViewAndBackingViewIsCreated(reactTag);
|
||||
super.sendAccessibilityEvent(reactTag, eventType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all children defined by moveFrom and removeFrom from a given parent,
|
||||
* preparing elements in moveFrom to be re-added at proper index.
|
||||
|
|
Loading…
Reference in New Issue