First implementation of scheduleWork method
Reviewed By: shergin Differential Revision: D7799412 fbshipit-source-id: b78a0bc0e80868f6877a31f862d7e6104fd4a049
This commit is contained in:
parent
58ea20b5e8
commit
a04ad8d8fb
|
@ -1,5 +1,13 @@
|
||||||
package com.facebook.react.fabric;
|
package com.facebook.react.fabric;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import com.facebook.react.bridge.ReactContext;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class allows Native code to schedule work in JS.
|
* This class allows Native code to schedule work in JS.
|
||||||
* Work (following JS naming) represents a task that needs to be executed in JS.
|
* Work (following JS naming) represents a task that needs to be executed in JS.
|
||||||
|
@ -7,23 +15,59 @@ package com.facebook.react.fabric;
|
||||||
* Four types of work are supported by this class:
|
* Four types of work are supported by this class:
|
||||||
*
|
*
|
||||||
* Synchronous:
|
* Synchronous:
|
||||||
* - Sync work -> flushSync
|
* - Sync work -> flushSync()
|
||||||
* - Work work -> flushSerial
|
* - Work work -> flushSerial()
|
||||||
*
|
*
|
||||||
* Asynchronous:
|
* Asynchronous:
|
||||||
* - Interactive work (serial): -> scheduleSerial
|
* - Interactive work (serial): -> scheduleSerial()
|
||||||
* - Deferred work: -> scheduleWork
|
* - Deferred work: -> scheduleWork()
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class Scheduler {
|
public class Scheduler {
|
||||||
|
|
||||||
public Scheduler() {
|
private static final String TAG = Scheduler.class.getSimpleName();
|
||||||
|
// The usage of this executor might change in the near future.
|
||||||
|
private final ExecutorService mExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<Runnable>());
|
||||||
|
private final ReactContext mReactContext;
|
||||||
|
|
||||||
|
public Scheduler(ReactContext reactContext) {
|
||||||
|
mReactContext = reactContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void scheduleWork(Work work) {
|
/**
|
||||||
// TODO T26717866 this method needs to be implemented. The current implementation is just for
|
* This method schedules work to be executed with the lowest priority in the JS Thread.
|
||||||
// testing purpose.
|
*
|
||||||
|
* The current implementation queues "work"s in an unbounded queue tight to a SingleThreadExecutor.
|
||||||
work.run();
|
* Work objects are going to be submitted one-by-one at the end of the JS Queue Thread.
|
||||||
|
*
|
||||||
|
* Notice that the current implementation might experience some delays in JS work execution,
|
||||||
|
* depending on the size of the JS Queue and the time it takes to execute each work in JS.
|
||||||
|
*
|
||||||
|
* TODO: This implementation is very likely to change in the near future.
|
||||||
|
*/
|
||||||
|
public void scheduleWork(final Work work) {
|
||||||
|
try {
|
||||||
|
mExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mReactContext.runOnJSQueueThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
work.run();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Log.w(TAG, "Exception running work in JS.", ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RejectedExecutionException ex) {
|
||||||
|
// This can happen if a Work is scheduled when the Scheduler is being shutdown.
|
||||||
|
// For now, we log and do not take any action.
|
||||||
|
Log.i(TAG, "Unable to schedule task.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flushSync(Work work) {
|
public void flushSync(Work work) {
|
||||||
|
@ -40,4 +84,12 @@ public class Scheduler {
|
||||||
// TODO T26717866 this method needs to be implemented. The current implementation is just for
|
// TODO T26717866 this method needs to be implemented. The current implementation is just for
|
||||||
// testing purpose.
|
// testing purpose.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdowns the {@link Scheduler}. this operation will attempt to stop all "active executing"
|
||||||
|
* Works items and it will "halts:" all the Works items waiting to be executed.
|
||||||
|
*/
|
||||||
|
public void shutdown() {
|
||||||
|
mExecutor.shutdownNow();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import android.annotation.TargetApi;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.bridge.WritableArray;
|
import com.facebook.react.bridge.WritableArray;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
|
@ -26,21 +27,23 @@ import com.facebook.react.fabric.FabricUIManager;
|
||||||
import com.facebook.react.fabric.Scheduler;
|
import com.facebook.react.fabric.Scheduler;
|
||||||
import com.facebook.react.fabric.Work;
|
import com.facebook.react.fabric.Work;
|
||||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.ECLAIR)
|
@TargetApi(Build.VERSION_CODES.ECLAIR)
|
||||||
public class FabricEventEmitter implements RCTEventEmitter {
|
public class FabricEventEmitter implements RCTEventEmitter, Closeable {
|
||||||
|
|
||||||
private static final String TAG = FabricEventEmitter.class.getSimpleName();
|
private static final String TAG = FabricEventEmitter.class.getSimpleName();
|
||||||
|
|
||||||
private final FabricUIManager mFabricUIManager;
|
private final FabricUIManager mFabricUIManager;
|
||||||
private final Scheduler mScheduler;
|
private final Scheduler mScheduler;
|
||||||
|
|
||||||
public FabricEventEmitter(Scheduler scheduler, FabricUIManager fabricUIManager) {
|
public FabricEventEmitter(ReactApplicationContext context, FabricUIManager fabricUIManager) {
|
||||||
mScheduler = scheduler;
|
mScheduler = new Scheduler(context);
|
||||||
mFabricUIManager = fabricUIManager;
|
mFabricUIManager = fabricUIManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +54,11 @@ public class FabricEventEmitter implements RCTEventEmitter {
|
||||||
mScheduler.scheduleWork(new FabricUIManagerWork(instanceHandle, eventName, params) );
|
mScheduler.scheduleWork(new FabricUIManagerWork(instanceHandle, eventName, params) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
mScheduler.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
private class FabricUIManagerWork implements Work {
|
private class FabricUIManagerWork implements Work {
|
||||||
private final int mInstanceHandle;
|
private final int mInstanceHandle;
|
||||||
private final String mEventName;
|
private final String mEventName;
|
||||||
|
|
|
@ -97,7 +97,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
||||||
|
|
||||||
private Event[] mEventsToDispatch = new Event[16];
|
private Event[] mEventsToDispatch = new Event[16];
|
||||||
private int mEventsToDispatchSize = 0;
|
private int mEventsToDispatchSize = 0;
|
||||||
private volatile @Nullable ReactEventEmitter mRCTEventEmitter = new ReactEventEmitter();
|
private volatile @Nullable ReactEventEmitter mReactEventEmitter = new ReactEventEmitter();
|
||||||
private short mNextEventTypeId = 0;
|
private short mNextEventTypeId = 0;
|
||||||
private volatile boolean mHasDispatchScheduled = false;
|
private volatile boolean mHasDispatchScheduled = false;
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
||||||
event.getEventName(),
|
event.getEventName(),
|
||||||
event.getUniqueID());
|
event.getUniqueID());
|
||||||
}
|
}
|
||||||
if (mRCTEventEmitter != null) {
|
if (mReactEventEmitter != null) {
|
||||||
// If the host activity is paused, the frame callback may not be currently
|
// If the host activity is paused, the frame callback may not be currently
|
||||||
// posted. Ensure that it is so that this event gets delivered promptly.
|
// posted. Ensure that it is so that this event gets delivered promptly.
|
||||||
mCurrentFrameCallback.maybePostFromNonUI();
|
mCurrentFrameCallback.maybePostFromNonUI();
|
||||||
|
@ -162,6 +162,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
||||||
@Override
|
@Override
|
||||||
public void onHostDestroy() {
|
public void onHostDestroy() {
|
||||||
stopFrameCallback();
|
stopFrameCallback();
|
||||||
|
mReactEventEmitter.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCatalystInstanceDestroyed() {
|
public void onCatalystInstanceDestroyed() {
|
||||||
|
@ -251,7 +252,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerEventEmitter(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) {
|
public void registerEventEmitter(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) {
|
||||||
mRCTEventEmitter.register(uiManagerType, eventEmitter);
|
mReactEventEmitter.register(uiManagerType, eventEmitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ScheduleDispatchFrameCallback extends ChoreographerCompat.FrameCallback {
|
private class ScheduleDispatchFrameCallback extends ChoreographerCompat.FrameCallback {
|
||||||
|
@ -331,7 +332,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
||||||
"ScheduleDispatchFrameCallback",
|
"ScheduleDispatchFrameCallback",
|
||||||
mHasDispatchScheduledCount.getAndIncrement());
|
mHasDispatchScheduledCount.getAndIncrement());
|
||||||
mHasDispatchScheduled = false;
|
mHasDispatchScheduled = false;
|
||||||
Assertions.assertNotNull(mRCTEventEmitter);
|
Assertions.assertNotNull(mReactEventEmitter);
|
||||||
synchronized (mEventsToDispatchLock) {
|
synchronized (mEventsToDispatchLock) {
|
||||||
// We avoid allocating an array and iterator, and "sorting" if we don't need to.
|
// We avoid allocating an array and iterator, and "sorting" if we don't need to.
|
||||||
// This occurs when the size of mEventsToDispatch is zero or one.
|
// This occurs when the size of mEventsToDispatch is zero or one.
|
||||||
|
@ -348,7 +349,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
||||||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||||
event.getEventName(),
|
event.getEventName(),
|
||||||
event.getUniqueID());
|
event.getUniqueID());
|
||||||
event.dispatch(mRCTEventEmitter);
|
event.dispatch(mReactEventEmitter);
|
||||||
event.dispose();
|
event.dispose();
|
||||||
}
|
}
|
||||||
clearEventsToDispatch();
|
clearEventsToDispatch();
|
||||||
|
|
|
@ -9,20 +9,23 @@ package com.facebook.react.uimanager.events;
|
||||||
|
|
||||||
import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
|
import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import com.facebook.infer.annotation.Assertions;
|
import com.facebook.infer.annotation.Assertions;
|
||||||
import com.facebook.react.bridge.WritableArray;
|
import com.facebook.react.bridge.WritableArray;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
import com.facebook.react.uimanager.common.UIManagerType;
|
import com.facebook.react.uimanager.common.UIManagerType;
|
||||||
import com.facebook.react.uimanager.common.ViewUtil;
|
import com.facebook.react.uimanager.common.ViewUtil;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class ReactEventEmitter implements RCTEventEmitter {
|
public class ReactEventEmitter implements RCTEventEmitter {
|
||||||
|
|
||||||
|
private static final String TAG = ReactEventEmitter.class.getSimpleName();
|
||||||
private final SparseArray<RCTEventEmitter> mEventEmitters = new SparseArray<>();
|
private final SparseArray<RCTEventEmitter> mEventEmitters = new SparseArray<>();
|
||||||
|
|
||||||
public ReactEventEmitter() {
|
public ReactEventEmitter() { }
|
||||||
}
|
|
||||||
|
|
||||||
public void register(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) {
|
public void register(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) {
|
||||||
mEventEmitters.put(uiManagerType, eventEmitter);
|
mEventEmitters.put(uiManagerType, eventEmitter);
|
||||||
|
@ -50,4 +53,16 @@ public class ReactEventEmitter implements RCTEventEmitter {
|
||||||
return mEventEmitters.get(type);
|
return mEventEmitters.get(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
for (int i = 0 ; i < mEventEmitters.size() ; i++) {
|
||||||
|
RCTEventEmitter eventEmitter = mEventEmitters.valueAt(i);
|
||||||
|
if (eventEmitter instanceof Closeable) {
|
||||||
|
try {
|
||||||
|
((Closeable) eventEmitter).close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.i(TAG, "Exception when closing EventEmitter: " + eventEmitter, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,14 @@
|
||||||
|
|
||||||
package com.facebook.react.views.image;
|
package com.facebook.react.views.image;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
|
|
||||||
import com.facebook.react.bridge.Arguments;
|
import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.WritableMap;
|
import com.facebook.react.bridge.WritableMap;
|
||||||
import com.facebook.react.uimanager.events.Event;
|
import com.facebook.react.uimanager.events.Event;
|
||||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class ImageLoadEvent extends Event<ImageLoadEvent> {
|
public class ImageLoadEvent extends Event<ImageLoadEvent> {
|
||||||
@IntDef({ON_ERROR, ON_LOAD, ON_LOAD_END, ON_LOAD_START, ON_PROGRESS})
|
@IntDef({ON_ERROR, ON_LOAD, ON_LOAD_END, ON_LOAD_START, ON_PROGRESS})
|
||||||
|
|
Loading…
Reference in New Issue