17
17
import com .facebook .react .bridge .Arguments ;
18
18
import com .facebook .react .bridge .Callback ;
19
19
import com .facebook .react .bridge .LifecycleEventListener ;
20
- import com .facebook .react .bridge .OnBatchCompleteListener ;
21
20
import com .facebook .react .bridge .ReactApplicationContext ;
22
21
import com .facebook .react .bridge .ReactContextBaseJavaModule ;
23
22
import com .facebook .react .bridge .ReactMethod ;
24
23
import com .facebook .react .bridge .ReadableMap ;
25
24
import com .facebook .react .bridge .WritableMap ;
25
+ import com .facebook .react .common .annotations .VisibleForTesting ;
26
26
import com .facebook .react .module .annotations .ReactModule ;
27
27
import com .facebook .react .modules .core .DeviceEventManagerModule ;
28
28
import com .facebook .react .modules .core .ReactChoreographer ;
29
29
import com .facebook .react .uimanager .GuardedFrameCallback ;
30
+ import com .facebook .react .uimanager .NativeViewHierarchyManager ;
31
+ import com .facebook .react .uimanager .UIBlock ;
30
32
import com .facebook .react .uimanager .UIManagerModule ;
33
+ import com .facebook .react .uimanager .UIManagerModuleListener ;
31
34
32
35
/**
33
36
* Module that exposes interface for creating and managing animated nodes on the "native" side.
72
75
*/
73
76
@ ReactModule (name = NativeAnimatedModule .NAME )
74
77
public class NativeAnimatedModule extends ReactContextBaseJavaModule implements
75
- OnBatchCompleteListener , LifecycleEventListener {
78
+ LifecycleEventListener , UIManagerModuleListener {
76
79
77
80
protected static final String NAME = "NativeAnimatedModule" ;
78
81
79
82
private interface UIThreadOperation {
80
83
void execute (NativeAnimatedNodesManager animatedNodesManager );
81
84
}
82
85
83
- private final Object mOperationsCopyLock = new Object ();
84
86
private final GuardedFrameCallback mAnimatedFrameCallback ;
85
87
private final ReactChoreographer mReactChoreographer ;
86
88
private ArrayList <UIThreadOperation > mOperations = new ArrayList <>();
87
- private volatile @ Nullable ArrayList <UIThreadOperation > mReadyOperations = null ;
89
+ private ArrayList <UIThreadOperation > mPreOperations = new ArrayList <>() ;
88
90
89
91
private @ Nullable NativeAnimatedNodesManager mNodesManager ;
90
92
@@ -95,26 +97,9 @@ public NativeAnimatedModule(ReactApplicationContext reactContext) {
95
97
mAnimatedFrameCallback = new GuardedFrameCallback (reactContext ) {
96
98
@ Override
97
99
protected void doFrameGuarded (final long frameTimeNanos ) {
98
- if (mNodesManager == null ) {
99
- UIManagerModule uiManager = getReactApplicationContext ()
100
- .getNativeModule (UIManagerModule .class );
101
- mNodesManager = new NativeAnimatedNodesManager (uiManager );
102
- }
103
-
104
- ArrayList <UIThreadOperation > operations ;
105
- synchronized (mOperationsCopyLock ) {
106
- operations = mReadyOperations ;
107
- mReadyOperations = null ;
108
- }
109
-
110
- if (operations != null ) {
111
- for (int i = 0 , size = operations .size (); i < size ; i ++) {
112
- operations .get (i ).execute (mNodesManager );
113
- }
114
- }
115
-
116
- if (mNodesManager .hasActiveAnimations ()) {
117
- mNodesManager .runUpdates (frameTimeNanos );
100
+ NativeAnimatedNodesManager nodesManager = getNodesManager ();
101
+ if (nodesManager .hasActiveAnimations ()) {
102
+ nodesManager .runUpdates (frameTimeNanos );
118
103
}
119
104
120
105
// TODO: Would be great to avoid adding this callback in case there are no active animations
@@ -130,7 +115,10 @@ protected void doFrameGuarded(final long frameTimeNanos) {
130
115
131
116
@ Override
132
117
public void initialize () {
133
- getReactApplicationContext ().addLifecycleEventListener (this );
118
+ ReactApplicationContext reactCtx = getReactApplicationContext ();
119
+ UIManagerModule uiManager = reactCtx .getNativeModule (UIManagerModule .class );
120
+ reactCtx .addLifecycleEventListener (this );
121
+ uiManager .addUIManagerListener (this );
134
122
}
135
123
136
124
@ Override
@@ -139,24 +127,32 @@ public void onHostResume() {
139
127
}
140
128
141
129
@ Override
142
- public void onBatchComplete () {
143
- // Note: The order of executing onBatchComplete handler (especially in terms of onBatchComplete
144
- // from the UIManagerModule) doesn't matter as we only enqueue operations for the UI thread to
145
- // be executed from here. Thanks to ReactChoreographer all the operations from here are going
146
- // to be executed *after* all the operations enqueued by UIManager as the callback type that we
147
- // use for ReactChoreographer (CallbackType.NATIVE_ANIMATED_MODULE) is run after callbacks that
148
- // UIManager uses.
149
- ArrayList <UIThreadOperation > operations = mOperations .isEmpty () ? null : mOperations ;
150
- if (operations != null ) {
151
- mOperations = new ArrayList <>();
152
- synchronized (mOperationsCopyLock ) {
153
- if (mReadyOperations == null ) {
154
- mReadyOperations = operations ;
155
- } else {
156
- mReadyOperations .addAll (operations );
130
+ public void willDispatchViewUpdates (final UIManagerModule uiManager ) {
131
+ if (mOperations .isEmpty () && mPreOperations .isEmpty ()) {
132
+ return ;
133
+ }
134
+ final ArrayList <UIThreadOperation > preOperations = mPreOperations ;
135
+ final ArrayList <UIThreadOperation > operations = mOperations ;
136
+ mPreOperations = new ArrayList <>();
137
+ mOperations = new ArrayList <>();
138
+ uiManager .prependUIBlock (new UIBlock () {
139
+ @ Override
140
+ public void execute (NativeViewHierarchyManager nativeViewHierarchyManager ) {
141
+ NativeAnimatedNodesManager nodesManager = getNodesManager ();
142
+ for (UIThreadOperation operation : preOperations ) {
143
+ operation .execute (nodesManager );
157
144
}
158
145
}
159
- }
146
+ });
147
+ uiManager .addUIBlock (new UIBlock () {
148
+ @ Override
149
+ public void execute (NativeViewHierarchyManager nativeViewHierarchyManager ) {
150
+ NativeAnimatedNodesManager nodesManager = getNodesManager ();
151
+ for (UIThreadOperation operation : operations ) {
152
+ operation .execute (nodesManager );
153
+ }
154
+ }
155
+ });
160
156
}
161
157
162
158
@ Override
@@ -174,6 +170,15 @@ public String getName() {
174
170
return NAME ;
175
171
}
176
172
173
+ private NativeAnimatedNodesManager getNodesManager () {
174
+ if (mNodesManager == null ) {
175
+ UIManagerModule uiManager = getReactApplicationContext ().getNativeModule (UIManagerModule .class );
176
+ mNodesManager = new NativeAnimatedNodesManager (uiManager );
177
+ }
178
+
179
+ return mNodesManager ;
180
+ }
181
+
177
182
private void clearFrameCallback () {
178
183
Assertions .assertNotNull (mReactChoreographer ).removeFrameCallback (
179
184
ReactChoreographer .CallbackType .NATIVE_ANIMATED_MODULE ,
@@ -186,6 +191,11 @@ private void enqueueFrameCallback() {
186
191
mAnimatedFrameCallback );
187
192
}
188
193
194
+ @ VisibleForTesting
195
+ public void setNodesManager (NativeAnimatedNodesManager nodesManager ) {
196
+ mNodesManager = nodesManager ;
197
+ }
198
+
189
199
@ ReactMethod
190
200
public void createAnimatedNode (final int tag , final ReadableMap config ) {
191
201
mOperations .add (new UIThreadOperation () {
@@ -336,6 +346,12 @@ public void execute(NativeAnimatedNodesManager animatedNodesManager) {
336
346
337
347
@ ReactMethod
338
348
public void disconnectAnimatedNodeFromView (final int animatedNodeTag , final int viewTag ) {
349
+ mPreOperations .add (new UIThreadOperation () {
350
+ @ Override
351
+ public void execute (NativeAnimatedNodesManager animatedNodesManager ) {
352
+ animatedNodesManager .restoreDefaultValues (animatedNodeTag , viewTag );
353
+ }
354
+ });
339
355
mOperations .add (new UIThreadOperation () {
340
356
@ Override
341
357
public void execute (NativeAnimatedNodesManager animatedNodesManager ) {
0 commit comments