Skip to content

Commit 248c324

Browse files
javachefacebook-github-bot
authored andcommitted
Remove ChoreographerCompat (#39775)
Summary: Pull Request resolved: #39775 ChoreographerCompat existed to support JellyBean, but given we target Android SDK 23+ now, this is safe to remove. Changelog: [Android][Removed] Deprecated ChoreographerCompat.FrameCallback, use Choreographer.FrameCallback Reviewed By: mdvacca Differential Revision: D49826889 fbshipit-source-id: 5158c470553327b70a199168f5b7ed7071cc8c48
1 parent 0e10ee6 commit 248c324

File tree

14 files changed

+117
-238
lines changed

14 files changed

+117
-238
lines changed

packages/react-native/ReactAndroid/src/androidTest/java/com/facebook/react/testing/idledetection/ReactIdleDetectionUtil.java

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99

1010
import android.app.Instrumentation;
1111
import android.os.SystemClock;
12+
import android.view.Choreographer;
1213
import androidx.test.InstrumentationRegistry;
1314
import com.facebook.react.bridge.ReactContext;
1415
import com.facebook.react.bridge.UiThreadUtil;
15-
import com.facebook.react.modules.core.ChoreographerCompat;
16+
import com.facebook.react.modules.core.ReactChoreographer;
1617
import java.util.concurrent.CountDownLatch;
1718
import java.util.concurrent.TimeUnit;
1819

@@ -48,26 +49,24 @@ private static void waitForChoreographer(long timeToWait) {
4849
final int waitFrameCount = 2;
4950
final CountDownLatch latch = new CountDownLatch(1);
5051
UiThreadUtil.runOnUiThread(
51-
new Runnable() {
52-
@Override
53-
public void run() {
54-
final ChoreographerCompat choreographerCompat = ChoreographerCompat.getInstance();
55-
choreographerCompat.postFrameCallback(
56-
new ChoreographerCompat.FrameCallback() {
52+
() -> {
53+
ReactChoreographer choreographer = ReactChoreographer.getInstance();
54+
choreographer.postFrameCallback(
55+
ReactChoreographer.CallbackType.IDLE_EVENT,
56+
new Choreographer.FrameCallback() {
57+
private int frameCount = 0;
5758

58-
private int frameCount = 0;
59-
60-
@Override
61-
public void doFrame(long frameTimeNanos) {
62-
frameCount++;
63-
if (frameCount == waitFrameCount) {
64-
latch.countDown();
65-
} else {
66-
choreographerCompat.postFrameCallback(this);
67-
}
59+
@Override
60+
public void doFrame(long frameTimeNanos) {
61+
frameCount++;
62+
if (frameCount == waitFrameCount) {
63+
latch.countDown();
64+
} else {
65+
choreographer.postFrameCallback(
66+
ReactChoreographer.CallbackType.IDLE_EVENT, this);
6867
}
69-
});
70-
}
68+
}
69+
});
7170
});
7271
try {
7372
if (!latch.await(timeToWait, TimeUnit.MILLISECONDS)) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/fabric/GuardedFrameCallback.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77

88
package com.facebook.react.fabric;
99

10+
import android.view.Choreographer;
1011
import androidx.annotation.NonNull;
1112
import com.facebook.react.bridge.JSExceptionHandler;
1213
import com.facebook.react.bridge.ReactContext;
13-
import com.facebook.react.modules.core.ChoreographerCompat;
1414

15-
public abstract class GuardedFrameCallback extends ChoreographerCompat.FrameCallback {
15+
public abstract class GuardedFrameCallback implements Choreographer.FrameCallback {
1616

1717
@NonNull private final JSExceptionHandler mExceptionHandler;
1818

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ChoreographerCompat.java

Lines changed: 3 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -5,107 +5,12 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
// This file was pulled from the facebook/rebound repository.
9-
108
package com.facebook.react.modules.core;
119

12-
import android.os.Handler;
1310
import android.view.Choreographer;
14-
import com.facebook.react.bridge.UiThreadUtil;
1511

16-
/**
17-
* Wrapper class for abstracting away availability of the JellyBean Choreographer. If Choreographer
18-
* is unavailable we fallback to using a normal Handler.
19-
*/
2012
public class ChoreographerCompat {
21-
22-
private static final long ONE_FRAME_MILLIS = 17;
23-
private static ChoreographerCompat sInstance;
24-
25-
private Handler mHandler;
26-
private Choreographer mChoreographer;
27-
28-
public static ChoreographerCompat getInstance() {
29-
UiThreadUtil.assertOnUiThread();
30-
if (sInstance == null) {
31-
sInstance = new ChoreographerCompat();
32-
}
33-
return sInstance;
34-
}
35-
36-
private ChoreographerCompat() {
37-
mChoreographer = getChoreographer();
38-
}
39-
40-
public void postFrameCallback(FrameCallback callbackWrapper) {
41-
choreographerPostFrameCallback(callbackWrapper.getFrameCallback());
42-
}
43-
44-
public void postFrameCallbackDelayed(FrameCallback callbackWrapper, long delayMillis) {
45-
choreographerPostFrameCallbackDelayed(callbackWrapper.getFrameCallback(), delayMillis);
46-
}
47-
48-
public void removeFrameCallback(FrameCallback callbackWrapper) {
49-
choreographerRemoveFrameCallback(callbackWrapper.getFrameCallback());
50-
}
51-
52-
private Choreographer getChoreographer() {
53-
return Choreographer.getInstance();
54-
}
55-
56-
private void choreographerPostFrameCallback(Choreographer.FrameCallback frameCallback) {
57-
mChoreographer.postFrameCallback(frameCallback);
58-
}
59-
60-
private void choreographerPostFrameCallbackDelayed(
61-
Choreographer.FrameCallback frameCallback, long delayMillis) {
62-
mChoreographer.postFrameCallbackDelayed(frameCallback, delayMillis);
63-
}
64-
65-
private void choreographerRemoveFrameCallback(Choreographer.FrameCallback frameCallback) {
66-
mChoreographer.removeFrameCallback(frameCallback);
67-
}
68-
69-
/**
70-
* This class provides a compatibility wrapper around the JellyBean FrameCallback with methods to
71-
* access cached wrappers for submitting a real FrameCallback to a Choreographer or a Runnable to
72-
* a Handler.
73-
*/
74-
public abstract static class FrameCallback {
75-
76-
private Runnable mRunnable;
77-
private Choreographer.FrameCallback mFrameCallback;
78-
79-
Choreographer.FrameCallback getFrameCallback() {
80-
if (mFrameCallback == null) {
81-
mFrameCallback =
82-
new Choreographer.FrameCallback() {
83-
@Override
84-
public void doFrame(long frameTimeNanos) {
85-
FrameCallback.this.doFrame(frameTimeNanos);
86-
}
87-
};
88-
}
89-
return mFrameCallback;
90-
}
91-
92-
Runnable getRunnable() {
93-
if (mRunnable == null) {
94-
mRunnable =
95-
new Runnable() {
96-
@Override
97-
public void run() {
98-
doFrame(System.nanoTime());
99-
}
100-
};
101-
}
102-
return mRunnable;
103-
}
104-
105-
/**
106-
* Just a wrapper for frame callback, see {@link
107-
* android.view.Choreographer.FrameCallback#doFrame(long)}.
108-
*/
109-
public abstract void doFrame(long frameTimeNanos);
110-
}
13+
/** @deprecated Use Choreographer.FrameCallback instead */
14+
@Deprecated
15+
public abstract static class FrameCallback implements Choreographer.FrameCallback {}
11116
}

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaTimerManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package com.facebook.react.modules.core;
99

1010
import android.util.SparseArray;
11+
import android.view.Choreographer;
1112
import androidx.annotation.Nullable;
1213
import com.facebook.proguard.annotations.DoNotStrip;
1314
import com.facebook.react.bridge.Arguments;
@@ -51,7 +52,7 @@ private Timer(int callbackID, long initialTargetTime, int duration, boolean repe
5152
}
5253
}
5354

54-
private class TimerFrameCallback extends ChoreographerCompat.FrameCallback {
55+
private class TimerFrameCallback implements Choreographer.FrameCallback {
5556

5657
// Temporary map for constructing the individual arrays of timers to call
5758
private @Nullable WritableArray mTimersToCall = null;
@@ -89,7 +90,7 @@ public void doFrame(long frameTimeNanos) {
8990
}
9091
}
9192

92-
private class IdleFrameCallback extends ChoreographerCompat.FrameCallback {
93+
private class IdleFrameCallback implements Choreographer.FrameCallback {
9394

9495
@Override
9596
public void doFrame(long frameTimeNanos) {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/ReactChoreographer.java

Lines changed: 53 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
package com.facebook.react.modules.core;
99

10-
import androidx.annotation.GuardedBy;
10+
import android.view.Choreographer;
1111
import androidx.annotation.Nullable;
1212
import com.facebook.common.logging.FLog;
1313
import com.facebook.infer.annotation.Assertions;
@@ -17,10 +17,10 @@
1717

1818
/**
1919
* A simple wrapper around Choreographer that allows us to control the order certain callbacks are
20-
* executed within a given frame. The main difference is that we enforce this is accessed from the
21-
* UI thread: this is because this ordering cannot be guaranteed across multiple threads.
20+
* executed within a given frame. The wrapped Choreographer instance will always be the main thread
21+
* one and the API's are safe to use from any thread.
2222
*/
23-
public class ReactChoreographer {
23+
public final class ReactChoreographer {
2424

2525
public enum CallbackType {
2626

@@ -67,37 +67,65 @@ public static ReactChoreographer getInstance() {
6767
}
6868

6969
// This needs to be volatile due to double checked locking issue - https://fburl.com/z409owpf
70-
private @Nullable volatile ChoreographerCompat mChoreographer;
71-
private final ReactChoreographerDispatcher mReactChoreographerDispatcher;
72-
private final Object mCallbackQueuesLock = new Object();
73-
74-
@GuardedBy("mCallbackQueuesLock")
75-
private final ArrayDeque<ChoreographerCompat.FrameCallback>[] mCallbackQueues;
70+
private @Nullable volatile Choreographer mChoreographer;
71+
72+
private final ArrayDeque<Choreographer.FrameCallback>[] mCallbackQueues;
73+
74+
private final Choreographer.FrameCallback mFrameCallback =
75+
new Choreographer.FrameCallback() {
76+
@Override
77+
public void doFrame(long frameTimeNanos) {
78+
synchronized (mCallbackQueues) {
79+
// Callbacks run once and are then automatically removed, the callback will
80+
// be posted again from postFrameCallback
81+
mHasPostedCallback = false;
82+
83+
for (int i = 0; i < mCallbackQueues.length; i++) {
84+
ArrayDeque<Choreographer.FrameCallback> callbackQueue = mCallbackQueues[i];
85+
int initialLength = callbackQueue.size();
86+
for (int callback = 0; callback < initialLength; callback++) {
87+
Choreographer.FrameCallback frameCallback = callbackQueue.pollFirst();
88+
if (frameCallback != null) {
89+
frameCallback.doFrame(frameTimeNanos);
90+
mTotalCallbacks--;
91+
} else {
92+
FLog.e(ReactConstants.TAG, "Tried to execute non-existent frame callback");
93+
}
94+
}
95+
}
96+
maybeRemoveFrameCallback();
97+
}
98+
}
99+
};
76100

77101
private int mTotalCallbacks = 0;
78102
private boolean mHasPostedCallback = false;
79103

80104
private ReactChoreographer() {
81-
mReactChoreographerDispatcher = new ReactChoreographerDispatcher();
82105
mCallbackQueues = new ArrayDeque[CallbackType.values().length];
83106
for (int i = 0; i < mCallbackQueues.length; i++) {
84107
mCallbackQueues[i] = new ArrayDeque<>();
85108
}
86-
initializeChoreographer(null);
109+
110+
UiThreadUtil.runOnUiThread(
111+
() -> {
112+
mChoreographer = Choreographer.getInstance();
113+
});
87114
}
88115

89-
public void postFrameCallback(
90-
CallbackType type, ChoreographerCompat.FrameCallback frameCallback) {
91-
synchronized (mCallbackQueuesLock) {
116+
public void postFrameCallback(CallbackType type, Choreographer.FrameCallback frameCallback) {
117+
synchronized (mCallbackQueues) {
92118
mCallbackQueues[type.getOrder()].addLast(frameCallback);
93119
mTotalCallbacks++;
94120
Assertions.assertCondition(mTotalCallbacks > 0);
121+
95122
if (!mHasPostedCallback) {
96123
if (mChoreographer == null) {
97-
initializeChoreographer(
98-
new Runnable() {
99-
@Override
100-
public void run() {
124+
// Schedule on the main thread, at which point the constructor's async work will have
125+
// completed
126+
UiThreadUtil.runOnUiThread(
127+
() -> {
128+
synchronized (mCallbackQueues) {
101129
postFrameCallbackOnChoreographer();
102130
}
103131
});
@@ -110,33 +138,15 @@ public void run() {
110138

111139
/**
112140
* This method writes on mHasPostedCallback and it should be called from another method that has
113-
* the lock mCallbackQueuesLock
141+
* the lock mCallbackQueues
114142
*/
115143
private void postFrameCallbackOnChoreographer() {
116-
mChoreographer.postFrameCallback(mReactChoreographerDispatcher);
144+
mChoreographer.postFrameCallback(mFrameCallback);
117145
mHasPostedCallback = true;
118146
}
119147

120-
public void initializeChoreographer(@Nullable final Runnable runnable) {
121-
UiThreadUtil.runOnUiThread(
122-
new Runnable() {
123-
@Override
124-
public void run() {
125-
synchronized (ReactChoreographer.class) {
126-
if (mChoreographer == null) {
127-
mChoreographer = ChoreographerCompat.getInstance();
128-
}
129-
}
130-
if (runnable != null) {
131-
runnable.run();
132-
}
133-
}
134-
});
135-
}
136-
137-
public void removeFrameCallback(
138-
CallbackType type, ChoreographerCompat.FrameCallback frameCallback) {
139-
synchronized (mCallbackQueuesLock) {
148+
public void removeFrameCallback(CallbackType type, Choreographer.FrameCallback frameCallback) {
149+
synchronized (mCallbackQueues) {
140150
if (mCallbackQueues[type.getOrder()].removeFirstOccurrence(frameCallback)) {
141151
mTotalCallbacks--;
142152
maybeRemoveFrameCallback();
@@ -148,39 +158,15 @@ public void removeFrameCallback(
148158

149159
/**
150160
* This method reads and writes on mHasPostedCallback and it should be called from another method
151-
* that already has the lock mCallbackQueuesLock.
161+
* that already has the lock on mCallbackQueues.
152162
*/
153163
private void maybeRemoveFrameCallback() {
154164
Assertions.assertCondition(mTotalCallbacks >= 0);
155165
if (mTotalCallbacks == 0 && mHasPostedCallback) {
156166
if (mChoreographer != null) {
157-
mChoreographer.removeFrameCallback(mReactChoreographerDispatcher);
167+
mChoreographer.removeFrameCallback(mFrameCallback);
158168
}
159169
mHasPostedCallback = false;
160170
}
161171
}
162-
163-
private class ReactChoreographerDispatcher extends ChoreographerCompat.FrameCallback {
164-
165-
@Override
166-
public void doFrame(long frameTimeNanos) {
167-
synchronized (mCallbackQueuesLock) {
168-
mHasPostedCallback = false;
169-
for (int i = 0; i < mCallbackQueues.length; i++) {
170-
ArrayDeque<ChoreographerCompat.FrameCallback> callbackQueue = mCallbackQueues[i];
171-
int initialLength = callbackQueue.size();
172-
for (int callback = 0; callback < initialLength; callback++) {
173-
ChoreographerCompat.FrameCallback frameCallback = callbackQueue.pollFirst();
174-
if (frameCallback != null) {
175-
frameCallback.doFrame(frameTimeNanos);
176-
mTotalCallbacks--;
177-
} else {
178-
FLog.e(ReactConstants.TAG, "Tried to execute non-existent frame callback");
179-
}
180-
}
181-
}
182-
maybeRemoveFrameCallback();
183-
}
184-
}
185-
}
186172
}

0 commit comments

Comments
 (0)