7
7
8
8
package com .facebook .react .modules .core ;
9
9
10
+ import com .facebook .react .bridge .UiThreadUtil ;
10
11
import java .util .ArrayDeque ;
12
+ import javax .annotation .Nullable ;
11
13
12
14
import com .facebook .common .logging .FLog ;
13
15
import com .facebook .infer .annotation .Assertions ;
14
- import com .facebook .react .bridge .UiThreadUtil ;
15
16
import com .facebook .react .common .ReactConstants ;
16
17
17
18
/**
@@ -65,7 +66,6 @@ private CallbackType(int order) {
65
66
66
67
public static void initialize () {
67
68
if (sInstance == null ) {
68
- UiThreadUtil .assertOnUiThread ();
69
69
sInstance = new ReactChoreographer ();
70
70
}
71
71
}
@@ -75,20 +75,21 @@ public static ReactChoreographer getInstance() {
75
75
return sInstance ;
76
76
}
77
77
78
- private final ChoreographerCompat mChoreographer ;
78
+ // This needs to be volatile due to double checked locking issue - https://fburl.com/z409owpf
79
+ private @ Nullable volatile ChoreographerCompat mChoreographer ;
79
80
private final ReactChoreographerDispatcher mReactChoreographerDispatcher ;
80
81
private final ArrayDeque <ChoreographerCompat .FrameCallback >[] mCallbackQueues ;
81
82
82
83
private int mTotalCallbacks = 0 ;
83
84
private boolean mHasPostedCallback = false ;
84
85
85
86
private ReactChoreographer () {
86
- mChoreographer = ChoreographerCompat .getInstance ();
87
87
mReactChoreographerDispatcher = new ReactChoreographerDispatcher ();
88
88
mCallbackQueues = new ArrayDeque [CallbackType .values ().length ];
89
89
for (int i = 0 ; i < mCallbackQueues .length ; i ++) {
90
90
mCallbackQueues [i ] = new ArrayDeque <>();
91
91
}
92
+ initializeChoreographer (null );
92
93
}
93
94
94
95
public synchronized void postFrameCallback (
@@ -98,11 +99,40 @@ public synchronized void postFrameCallback(
98
99
mTotalCallbacks ++;
99
100
Assertions .assertCondition (mTotalCallbacks > 0 );
100
101
if (!mHasPostedCallback ) {
101
- mChoreographer .postFrameCallback (mReactChoreographerDispatcher );
102
- mHasPostedCallback = true ;
102
+ if (mChoreographer == null ) {
103
+ initializeChoreographer (new Runnable (){
104
+ @ Override
105
+ public void run () {
106
+ postFrameCallbackOnChoreographer ();
107
+ }
108
+ });
109
+ } else {
110
+ postFrameCallbackOnChoreographer ();
111
+ }
103
112
}
104
113
}
105
114
115
+ public void postFrameCallbackOnChoreographer () {
116
+ mChoreographer .postFrameCallback (mReactChoreographerDispatcher );
117
+ mHasPostedCallback = true ;
118
+ }
119
+
120
+ public void initializeChoreographer (@ Nullable final Runnable runnable ) {
121
+ UiThreadUtil .runOnUiThread (new Runnable () {
122
+ @ Override
123
+ public void run () {
124
+ synchronized (ReactChoreographer .class ) {
125
+ if (mChoreographer == null ) {
126
+ mChoreographer = ChoreographerCompat .getInstance ();
127
+ }
128
+ }
129
+ if (runnable != null ) {
130
+ runnable .run ();
131
+ }
132
+ }
133
+ });
134
+ }
135
+
106
136
public synchronized void removeFrameCallback (
107
137
CallbackType type ,
108
138
ChoreographerCompat .FrameCallback frameCallback ) {
@@ -117,7 +147,9 @@ public synchronized void removeFrameCallback(
117
147
private void maybeRemoveFrameCallback () {
118
148
Assertions .assertCondition (mTotalCallbacks >= 0 );
119
149
if (mTotalCallbacks == 0 && mHasPostedCallback ) {
120
- mChoreographer .removeFrameCallback (mReactChoreographerDispatcher );
150
+ if (mChoreographer != null ) {
151
+ mChoreographer .removeFrameCallback (mReactChoreographerDispatcher );
152
+ }
121
153
mHasPostedCallback = false ;
122
154
}
123
155
}
0 commit comments