Initialize the Choreographer in ReactChoreographer lazily

Summary:
Today, ReactInstanceManager calls `ReactChoreographer.initialize()` in its constructor. Since `ReactChoreographer` also needs to run on the UI thread, this forces the entire `ReactInstanceManager` to run on the UI thread.

By moving `ReactChoreographer` to lazily set up its Choreographer, we can make `ReactInstanceManager` run on any thread

Reviewed By: mdvacca

Differential Revision: D10097432

fbshipit-source-id: eb8c80aafcba745ea15c86296d11c487329b1df0
This commit is contained in:
Ram N 2018-10-12 19:35:50 -07:00 committed by Facebook Github Bot
parent c8b6d606a0
commit 5e7c774d64
2 changed files with 46 additions and 9 deletions

View File

@ -13,6 +13,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.Choreographer;
import com.facebook.react.bridge.UiThreadUtil;
/**
* Wrapper class for abstracting away availability of the JellyBean Choreographer. If Choreographer
@ -23,13 +24,17 @@ public class ChoreographerCompat {
private static final long ONE_FRAME_MILLIS = 17;
private static final boolean IS_JELLYBEAN_OR_HIGHER =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
private static final ChoreographerCompat INSTANCE = new ChoreographerCompat();
private static ChoreographerCompat sInstance;
private Handler mHandler;
private Choreographer mChoreographer;
public static ChoreographerCompat getInstance() {
return INSTANCE;
UiThreadUtil.assertOnUiThread();
if (sInstance == null){
sInstance = new ChoreographerCompat();
}
return sInstance;
}
private ChoreographerCompat() {

View File

@ -7,11 +7,12 @@
package com.facebook.react.modules.core;
import com.facebook.react.bridge.UiThreadUtil;
import java.util.ArrayDeque;
import javax.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.ReactConstants;
/**
@ -65,7 +66,6 @@ public class ReactChoreographer {
public static void initialize() {
if (sInstance == null) {
UiThreadUtil.assertOnUiThread();
sInstance = new ReactChoreographer();
}
}
@ -75,7 +75,8 @@ public class ReactChoreographer {
return sInstance;
}
private final ChoreographerCompat mChoreographer;
// This needs to be volatile due to double checked locking issue - https://fburl.com/z409owpf
private @Nullable volatile ChoreographerCompat mChoreographer;
private final ReactChoreographerDispatcher mReactChoreographerDispatcher;
private final ArrayDeque<ChoreographerCompat.FrameCallback>[] mCallbackQueues;
@ -83,12 +84,12 @@ public class ReactChoreographer {
private boolean mHasPostedCallback = false;
private ReactChoreographer() {
mChoreographer = ChoreographerCompat.getInstance();
mReactChoreographerDispatcher = new ReactChoreographerDispatcher();
mCallbackQueues = new ArrayDeque[CallbackType.values().length];
for (int i = 0; i < mCallbackQueues.length; i++) {
mCallbackQueues[i] = new ArrayDeque<>();
}
initializeChoreographer(null);
}
public synchronized void postFrameCallback(
@ -98,11 +99,40 @@ public class ReactChoreographer {
mTotalCallbacks++;
Assertions.assertCondition(mTotalCallbacks > 0);
if (!mHasPostedCallback) {
mChoreographer.postFrameCallback(mReactChoreographerDispatcher);
mHasPostedCallback = true;
if (mChoreographer == null) {
initializeChoreographer(new Runnable(){
@Override
public void run() {
postFrameCallbackOnChoreographer();
}
});
} else {
postFrameCallbackOnChoreographer();
}
}
}
public void postFrameCallbackOnChoreographer() {
mChoreographer.postFrameCallback(mReactChoreographerDispatcher);
mHasPostedCallback = true;
}
public void initializeChoreographer(@Nullable final Runnable runnable) {
UiThreadUtil.runOnUiThread(new Runnable() {
@Override
public void run() {
synchronized (ReactChoreographer.class) {
if (mChoreographer == null) {
mChoreographer = ChoreographerCompat.getInstance();
}
}
if (runnable != null) {
runnable.run();
}
}
});
}
public synchronized void removeFrameCallback(
CallbackType type,
ChoreographerCompat.FrameCallback frameCallback) {
@ -117,7 +147,9 @@ public class ReactChoreographer {
private void maybeRemoveFrameCallback() {
Assertions.assertCondition(mTotalCallbacks >= 0);
if (mTotalCallbacks == 0 && mHasPostedCallback) {
mChoreographer.removeFrameCallback(mReactChoreographerDispatcher);
if (mChoreographer != null) {
mChoreographer.removeFrameCallback(mReactChoreographerDispatcher);
}
mHasPostedCallback = false;
}
}