43
43
* shadow node hierarchy that is then mapped to a native view hierarchy.
44
44
*/
45
45
public class UIImplementation {
46
+ protected Object uiImplementationThreadLock = new Object ();
46
47
47
48
protected final EventDispatcher mEventDispatcher ;
48
49
protected final ReactApplicationContext mReactContext ;
@@ -197,23 +198,25 @@ public void updateRootView(
197
198
*/
198
199
public <T extends SizeMonitoringFrameLayout & MeasureSpecProvider > void registerRootView (
199
200
T rootView , int tag , ThemedReactContext context ) {
200
- final ReactShadowNode rootCSSNode = createRootShadowNode ();
201
- rootCSSNode .setReactTag (tag );
202
- rootCSSNode .setThemedContext (context );
203
-
204
- int widthMeasureSpec = rootView .getWidthMeasureSpec ();
205
- int heightMeasureSpec = rootView .getHeightMeasureSpec ();
206
- updateRootView (rootCSSNode , widthMeasureSpec , heightMeasureSpec );
207
-
208
- context .runOnNativeModulesQueueThread (new Runnable () {
209
- @ Override
210
- public void run () {
211
- mShadowNodeRegistry .addRootNode (rootCSSNode );
212
- }
213
- });
201
+ synchronized (uiImplementationThreadLock ) {
202
+ final ReactShadowNode rootCSSNode = createRootShadowNode ();
203
+ rootCSSNode .setReactTag (tag );
204
+ rootCSSNode .setThemedContext (context );
205
+
206
+ int widthMeasureSpec = rootView .getWidthMeasureSpec ();
207
+ int heightMeasureSpec = rootView .getHeightMeasureSpec ();
208
+ updateRootView (rootCSSNode , widthMeasureSpec , heightMeasureSpec );
209
+
210
+ context .runOnNativeModulesQueueThread (new Runnable () {
211
+ @ Override
212
+ public void run () {
213
+ mShadowNodeRegistry .addRootNode (rootCSSNode );
214
+ }
215
+ });
214
216
215
- // register it within NativeViewHierarchyManager
216
- mOperationsQueue .addRootView (tag , rootView , context );
217
+ // register it within NativeViewHierarchyManager
218
+ mOperationsQueue .addRootView (tag , rootView , context );
219
+ }
217
220
}
218
221
219
222
/**
@@ -228,7 +231,9 @@ public void removeRootView(int rootViewTag) {
228
231
* Unregisters a root node with a given tag from the shadow node registry
229
232
*/
230
233
public void removeRootShadowNode (int rootViewTag ) {
231
- mShadowNodeRegistry .removeRootNode (rootViewTag );
234
+ synchronized (uiImplementationThreadLock ) {
235
+ mShadowNodeRegistry .removeRootNode (rootViewTag );
236
+ }
232
237
}
233
238
234
239
/**
@@ -279,23 +284,25 @@ public Map<String, Long> getProfiledBatchPerfCounters() {
279
284
* Invoked by React to create a new node with a given tag, class name and properties.
280
285
*/
281
286
public void createView (int tag , String className , int rootViewTag , ReadableMap props ) {
282
- ReactShadowNode cssNode = createShadowNode (className );
283
- ReactShadowNode rootNode = mShadowNodeRegistry .getNode (rootViewTag );
284
- Assertions .assertNotNull (rootNode , "Root node with tag " + rootViewTag + " doesn't exist" );
285
- cssNode .setReactTag (tag );
286
- cssNode .setViewClassName (className );
287
- cssNode .setRootTag (rootNode .getReactTag ());
288
- cssNode .setThemedContext (rootNode .getThemedContext ());
289
-
290
- mShadowNodeRegistry .addNode (cssNode );
287
+ synchronized (uiImplementationThreadLock ) {
288
+ ReactShadowNode cssNode = createShadowNode (className );
289
+ ReactShadowNode rootNode = mShadowNodeRegistry .getNode (rootViewTag );
290
+ Assertions .assertNotNull (rootNode , "Root node with tag " + rootViewTag + " doesn't exist" );
291
+ cssNode .setReactTag (tag );
292
+ cssNode .setViewClassName (className );
293
+ cssNode .setRootTag (rootNode .getReactTag ());
294
+ cssNode .setThemedContext (rootNode .getThemedContext ());
295
+
296
+ mShadowNodeRegistry .addNode (cssNode );
297
+
298
+ ReactStylesDiffMap styles = null ;
299
+ if (props != null ) {
300
+ styles = new ReactStylesDiffMap (props );
301
+ cssNode .updateProperties (styles );
302
+ }
291
303
292
- ReactStylesDiffMap styles = null ;
293
- if (props != null ) {
294
- styles = new ReactStylesDiffMap (props );
295
- cssNode .updateProperties (styles );
304
+ handleCreateView (cssNode , rootViewTag , styles );
296
305
}
297
-
298
- handleCreateView (cssNode , rootViewTag , styles );
299
306
}
300
307
301
308
protected void handleCreateView (
@@ -363,106 +370,108 @@ public void manageChildren(
363
370
@ Nullable ReadableArray addChildTags ,
364
371
@ Nullable ReadableArray addAtIndices ,
365
372
@ Nullable ReadableArray removeFrom ) {
366
- ReactShadowNode cssNodeToManage = mShadowNodeRegistry .getNode (viewTag );
373
+ synchronized (uiImplementationThreadLock ) {
374
+ ReactShadowNode cssNodeToManage = mShadowNodeRegistry .getNode (viewTag );
367
375
368
- int numToMove = moveFrom == null ? 0 : moveFrom .size ();
369
- int numToAdd = addChildTags == null ? 0 : addChildTags .size ();
370
- int numToRemove = removeFrom == null ? 0 : removeFrom .size ();
376
+ int numToMove = moveFrom == null ? 0 : moveFrom .size ();
377
+ int numToAdd = addChildTags == null ? 0 : addChildTags .size ();
378
+ int numToRemove = removeFrom == null ? 0 : removeFrom .size ();
371
379
372
- if (numToMove != 0 && (moveTo == null || numToMove != moveTo .size ())) {
373
- throw new IllegalViewOperationException ("Size of moveFrom != size of moveTo!" );
374
- }
380
+ if (numToMove != 0 && (moveTo == null || numToMove != moveTo .size ())) {
381
+ throw new IllegalViewOperationException ("Size of moveFrom != size of moveTo!" );
382
+ }
375
383
376
- if (numToAdd != 0 && (addAtIndices == null || numToAdd != addAtIndices .size ())) {
377
- throw new IllegalViewOperationException ("Size of addChildTags != size of addAtIndices!" );
378
- }
384
+ if (numToAdd != 0 && (addAtIndices == null || numToAdd != addAtIndices .size ())) {
385
+ throw new IllegalViewOperationException ("Size of addChildTags != size of addAtIndices!" );
386
+ }
379
387
380
- // We treat moves as an add and a delete
381
- ViewAtIndex [] viewsToAdd = new ViewAtIndex [numToMove + numToAdd ];
382
- int [] indicesToRemove = new int [numToMove + numToRemove ];
383
- int [] tagsToRemove = new int [indicesToRemove .length ];
384
- int [] tagsToDelete = new int [numToRemove ];
385
-
386
- if (numToMove > 0 ) {
387
- Assertions .assertNotNull (moveFrom );
388
- Assertions .assertNotNull (moveTo );
389
- for (int i = 0 ; i < numToMove ; i ++) {
390
- int moveFromIndex = moveFrom .getInt (i );
391
- int tagToMove = cssNodeToManage .getChildAt (moveFromIndex ).getReactTag ();
392
- viewsToAdd [i ] = new ViewAtIndex (
393
- tagToMove ,
394
- moveTo .getInt (i ));
395
- indicesToRemove [i ] = moveFromIndex ;
396
- tagsToRemove [i ] = tagToMove ;
388
+ // We treat moves as an add and a delete
389
+ ViewAtIndex [] viewsToAdd = new ViewAtIndex [numToMove + numToAdd ];
390
+ int [] indicesToRemove = new int [numToMove + numToRemove ];
391
+ int [] tagsToRemove = new int [indicesToRemove .length ];
392
+ int [] tagsToDelete = new int [numToRemove ];
393
+
394
+ if (numToMove > 0 ) {
395
+ Assertions .assertNotNull (moveFrom );
396
+ Assertions .assertNotNull (moveTo );
397
+ for (int i = 0 ; i < numToMove ; i ++) {
398
+ int moveFromIndex = moveFrom .getInt (i );
399
+ int tagToMove = cssNodeToManage .getChildAt (moveFromIndex ).getReactTag ();
400
+ viewsToAdd [i ] = new ViewAtIndex (
401
+ tagToMove ,
402
+ moveTo .getInt (i ));
403
+ indicesToRemove [i ] = moveFromIndex ;
404
+ tagsToRemove [i ] = tagToMove ;
405
+ }
397
406
}
398
- }
399
407
400
- if (numToAdd > 0 ) {
401
- Assertions .assertNotNull (addChildTags );
402
- Assertions .assertNotNull (addAtIndices );
403
- for (int i = 0 ; i < numToAdd ; i ++) {
404
- int viewTagToAdd = addChildTags .getInt (i );
405
- int indexToAddAt = addAtIndices .getInt (i );
406
- viewsToAdd [numToMove + i ] = new ViewAtIndex (viewTagToAdd , indexToAddAt );
408
+ if (numToAdd > 0 ) {
409
+ Assertions .assertNotNull (addChildTags );
410
+ Assertions .assertNotNull (addAtIndices );
411
+ for (int i = 0 ; i < numToAdd ; i ++) {
412
+ int viewTagToAdd = addChildTags .getInt (i );
413
+ int indexToAddAt = addAtIndices .getInt (i );
414
+ viewsToAdd [numToMove + i ] = new ViewAtIndex (viewTagToAdd , indexToAddAt );
415
+ }
407
416
}
408
- }
409
417
410
- if (numToRemove > 0 ) {
411
- Assertions .assertNotNull (removeFrom );
412
- for (int i = 0 ; i < numToRemove ; i ++) {
413
- int indexToRemove = removeFrom .getInt (i );
414
- int tagToRemove = cssNodeToManage .getChildAt (indexToRemove ).getReactTag ();
415
- indicesToRemove [numToMove + i ] = indexToRemove ;
416
- tagsToRemove [numToMove + i ] = tagToRemove ;
417
- tagsToDelete [i ] = tagToRemove ;
418
+ if (numToRemove > 0 ) {
419
+ Assertions .assertNotNull (removeFrom );
420
+ for (int i = 0 ; i < numToRemove ; i ++) {
421
+ int indexToRemove = removeFrom .getInt (i );
422
+ int tagToRemove = cssNodeToManage .getChildAt (indexToRemove ).getReactTag ();
423
+ indicesToRemove [numToMove + i ] = indexToRemove ;
424
+ tagsToRemove [numToMove + i ] = tagToRemove ;
425
+ tagsToDelete [i ] = tagToRemove ;
426
+ }
418
427
}
419
- }
420
428
421
- // NB: moveFrom and removeFrom are both relative to the starting state of the View's children.
422
- // moveTo and addAt are both relative to the final state of the View's children.
423
- //
424
- // 1) Sort the views to add and indices to remove by index
425
- // 2) Iterate the indices being removed from high to low and remove them. Going high to low
426
- // makes sure we remove the correct index when there are multiple to remove.
427
- // 3) Iterate the views being added by index low to high and add them. Like the view removal,
428
- // iteration direction is important to preserve the correct index.
429
-
430
- Arrays .sort (viewsToAdd , ViewAtIndex .COMPARATOR );
431
- Arrays .sort (indicesToRemove );
432
-
433
- // Apply changes to CSSNodeDEPRECATED hierarchy
434
- int lastIndexRemoved = -1 ;
435
- for (int i = indicesToRemove .length - 1 ; i >= 0 ; i --) {
436
- int indexToRemove = indicesToRemove [i ];
437
- if (indexToRemove == lastIndexRemoved ) {
438
- throw new IllegalViewOperationException ("Repeated indices in Removal list for view tag: "
439
- + viewTag );
429
+ // NB: moveFrom and removeFrom are both relative to the starting state of the View's children.
430
+ // moveTo and addAt are both relative to the final state of the View's children.
431
+ //
432
+ // 1) Sort the views to add and indices to remove by index
433
+ // 2) Iterate the indices being removed from high to low and remove them. Going high to low
434
+ // makes sure we remove the correct index when there are multiple to remove.
435
+ // 3) Iterate the views being added by index low to high and add them. Like the view removal,
436
+ // iteration direction is important to preserve the correct index.
437
+
438
+ Arrays .sort (viewsToAdd , ViewAtIndex .COMPARATOR );
439
+ Arrays .sort (indicesToRemove );
440
+
441
+ // Apply changes to CSSNodeDEPRECATED hierarchy
442
+ int lastIndexRemoved = -1 ;
443
+ for (int i = indicesToRemove .length - 1 ; i >= 0 ; i --) {
444
+ int indexToRemove = indicesToRemove [i ];
445
+ if (indexToRemove == lastIndexRemoved ) {
446
+ throw new IllegalViewOperationException ("Repeated indices in Removal list for view tag: "
447
+ + viewTag );
448
+ }
449
+ cssNodeToManage .removeChildAt (indicesToRemove [i ]);
450
+ lastIndexRemoved = indicesToRemove [i ];
440
451
}
441
- cssNodeToManage .removeChildAt (indicesToRemove [i ]);
442
- lastIndexRemoved = indicesToRemove [i ];
443
- }
444
452
445
- for (int i = 0 ; i < viewsToAdd .length ; i ++) {
446
- ViewAtIndex viewAtIndex = viewsToAdd [i ];
447
- ReactShadowNode cssNodeToAdd = mShadowNodeRegistry .getNode (viewAtIndex .mTag );
448
- if (cssNodeToAdd == null ) {
449
- throw new IllegalViewOperationException ("Trying to add unknown view tag: "
450
- + viewAtIndex .mTag );
453
+ for (int i = 0 ; i < viewsToAdd .length ; i ++) {
454
+ ViewAtIndex viewAtIndex = viewsToAdd [i ];
455
+ ReactShadowNode cssNodeToAdd = mShadowNodeRegistry .getNode (viewAtIndex .mTag );
456
+ if (cssNodeToAdd == null ) {
457
+ throw new IllegalViewOperationException ("Trying to add unknown view tag: "
458
+ + viewAtIndex .mTag );
459
+ }
460
+ cssNodeToManage .addChildAt (cssNodeToAdd , viewAtIndex .mIndex );
451
461
}
452
- cssNodeToManage .addChildAt (cssNodeToAdd , viewAtIndex .mIndex );
453
- }
454
462
455
- if (!cssNodeToManage .isVirtual () && !cssNodeToManage .isVirtualAnchor ()) {
456
- mNativeViewHierarchyOptimizer .handleManageChildren (
457
- cssNodeToManage ,
458
- indicesToRemove ,
459
- tagsToRemove ,
460
- viewsToAdd ,
461
- tagsToDelete );
462
- }
463
+ if (!cssNodeToManage .isVirtual () && !cssNodeToManage .isVirtualAnchor ()) {
464
+ mNativeViewHierarchyOptimizer .handleManageChildren (
465
+ cssNodeToManage ,
466
+ indicesToRemove ,
467
+ tagsToRemove ,
468
+ viewsToAdd ,
469
+ tagsToDelete );
470
+ }
463
471
464
- for (int i = 0 ; i < tagsToDelete .length ; i ++) {
465
- removeShadowNode (mShadowNodeRegistry .getNode (tagsToDelete [i ]));
472
+ for (int i = 0 ; i < tagsToDelete .length ; i ++) {
473
+ removeShadowNode (mShadowNodeRegistry .getNode (tagsToDelete [i ]));
474
+ }
466
475
}
467
476
}
468
477
@@ -476,22 +485,23 @@ public void manageChildren(
476
485
public void setChildren (
477
486
int viewTag ,
478
487
ReadableArray childrenTags ) {
479
-
480
- ReactShadowNode cssNodeToManage = mShadowNodeRegistry .getNode (viewTag );
481
-
482
- for (int i = 0 ; i < childrenTags .size (); i ++) {
483
- ReactShadowNode cssNodeToAdd = mShadowNodeRegistry .getNode (childrenTags .getInt (i ));
484
- if (cssNodeToAdd == null ) {
485
- throw new IllegalViewOperationException ("Trying to add unknown view tag: "
486
- + childrenTags .getInt (i ));
488
+ synchronized (uiImplementationThreadLock ) {
489
+ ReactShadowNode cssNodeToManage = mShadowNodeRegistry .getNode (viewTag );
490
+
491
+ for (int i = 0 ; i < childrenTags .size (); i ++) {
492
+ ReactShadowNode cssNodeToAdd = mShadowNodeRegistry .getNode (childrenTags .getInt (i ));
493
+ if (cssNodeToAdd == null ) {
494
+ throw new IllegalViewOperationException ("Trying to add unknown view tag: "
495
+ + childrenTags .getInt (i ));
496
+ }
497
+ cssNodeToManage .addChildAt (cssNodeToAdd , i );
487
498
}
488
- cssNodeToManage .addChildAt (cssNodeToAdd , i );
489
- }
490
499
491
- if (!cssNodeToManage .isVirtual () && !cssNodeToManage .isVirtualAnchor ()) {
492
- mNativeViewHierarchyOptimizer .handleSetChildren (
493
- cssNodeToManage ,
494
- childrenTags );
500
+ if (!cssNodeToManage .isVirtual () && !cssNodeToManage .isVirtualAnchor ()) {
501
+ mNativeViewHierarchyOptimizer .handleSetChildren (
502
+ cssNodeToManage ,
503
+ childrenTags );
504
+ }
495
505
}
496
506
}
497
507
0 commit comments