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;
|
||||
|
||||
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.
|
||||
* 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:
|
||||
*
|
||||
* Synchronous:
|
||||
* - Sync work -> flushSync
|
||||
* - Work work -> flushSerial
|
||||
* - Sync work -> flushSync()
|
||||
* - Work work -> flushSerial()
|
||||
*
|
||||
* Asynchronous:
|
||||
* - Interactive work (serial): -> scheduleSerial
|
||||
* - Deferred work: -> scheduleWork
|
||||
* - Interactive work (serial): -> scheduleSerial()
|
||||
* - Deferred work: -> scheduleWork()
|
||||
*
|
||||
*/
|
||||
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
|
||||
// testing purpose.
|
||||
|
||||
work.run();
|
||||
/**
|
||||
* This method schedules work to be executed with the lowest priority in the JS Thread.
|
||||
*
|
||||
* The current implementation queues "work"s in an unbounded queue tight to a SingleThreadExecutor.
|
||||
* 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) {
|
||||
|
@ -40,4 +84,12 @@ public class Scheduler {
|
|||
// TODO T26717866 this method needs to be implemented. The current implementation is just for
|
||||
// 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.util.Log;
|
||||
import android.util.Pair;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
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.Work;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@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 final FabricUIManager mFabricUIManager;
|
||||
private final Scheduler mScheduler;
|
||||
|
||||
public FabricEventEmitter(Scheduler scheduler, FabricUIManager fabricUIManager) {
|
||||
mScheduler = scheduler;
|
||||
public FabricEventEmitter(ReactApplicationContext context, FabricUIManager fabricUIManager) {
|
||||
mScheduler = new Scheduler(context);
|
||||
mFabricUIManager = fabricUIManager;
|
||||
}
|
||||
|
||||
|
@ -51,6 +54,11 @@ public class FabricEventEmitter implements RCTEventEmitter {
|
|||
mScheduler.scheduleWork(new FabricUIManagerWork(instanceHandle, eventName, params) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mScheduler.shutdown();
|
||||
}
|
||||
|
||||
private class FabricUIManagerWork implements Work {
|
||||
private final int mInstanceHandle;
|
||||
private final String mEventName;
|
||||
|
|
|
@ -97,7 +97,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
|||
|
||||
private Event[] mEventsToDispatch = new Event[16];
|
||||
private int mEventsToDispatchSize = 0;
|
||||
private volatile @Nullable ReactEventEmitter mRCTEventEmitter = new ReactEventEmitter();
|
||||
private volatile @Nullable ReactEventEmitter mReactEventEmitter = new ReactEventEmitter();
|
||||
private short mNextEventTypeId = 0;
|
||||
private volatile boolean mHasDispatchScheduled = false;
|
||||
|
||||
|
@ -123,7 +123,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
|||
event.getEventName(),
|
||||
event.getUniqueID());
|
||||
}
|
||||
if (mRCTEventEmitter != null) {
|
||||
if (mReactEventEmitter != null) {
|
||||
// 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.
|
||||
mCurrentFrameCallback.maybePostFromNonUI();
|
||||
|
@ -162,6 +162,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
|||
@Override
|
||||
public void onHostDestroy() {
|
||||
stopFrameCallback();
|
||||
mReactEventEmitter.stop();
|
||||
}
|
||||
|
||||
public void onCatalystInstanceDestroyed() {
|
||||
|
@ -251,7 +252,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
|||
}
|
||||
|
||||
public void registerEventEmitter(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) {
|
||||
mRCTEventEmitter.register(uiManagerType, eventEmitter);
|
||||
mReactEventEmitter.register(uiManagerType, eventEmitter);
|
||||
}
|
||||
|
||||
private class ScheduleDispatchFrameCallback extends ChoreographerCompat.FrameCallback {
|
||||
|
@ -331,7 +332,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
|||
"ScheduleDispatchFrameCallback",
|
||||
mHasDispatchScheduledCount.getAndIncrement());
|
||||
mHasDispatchScheduled = false;
|
||||
Assertions.assertNotNull(mRCTEventEmitter);
|
||||
Assertions.assertNotNull(mReactEventEmitter);
|
||||
synchronized (mEventsToDispatchLock) {
|
||||
// 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.
|
||||
|
@ -348,7 +349,7 @@ public class EventDispatcher implements LifecycleEventListener,
|
|||
Systrace.TRACE_TAG_REACT_JAVA_BRIDGE,
|
||||
event.getEventName(),
|
||||
event.getUniqueID());
|
||||
event.dispatch(mRCTEventEmitter);
|
||||
event.dispatch(mReactEventEmitter);
|
||||
event.dispose();
|
||||
}
|
||||
clearEventsToDispatch();
|
||||
|
|
|
@ -9,20 +9,23 @@ package com.facebook.react.uimanager.events;
|
|||
|
||||
import static com.facebook.react.uimanager.events.TouchesHelper.TARGET_KEY;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.uimanager.common.UIManagerType;
|
||||
import com.facebook.react.uimanager.common.ViewUtil;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ReactEventEmitter implements RCTEventEmitter {
|
||||
|
||||
private static final String TAG = ReactEventEmitter.class.getSimpleName();
|
||||
private final SparseArray<RCTEventEmitter> mEventEmitters = new SparseArray<>();
|
||||
|
||||
public ReactEventEmitter() {
|
||||
}
|
||||
public ReactEventEmitter() { }
|
||||
|
||||
public void register(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) {
|
||||
mEventEmitters.put(uiManagerType, eventEmitter);
|
||||
|
@ -50,4 +53,16 @@ public class ReactEventEmitter implements RCTEventEmitter {
|
|||
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;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.support.annotation.IntDef;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ImageLoadEvent extends Event<ImageLoadEvent> {
|
||||
@IntDef({ON_ERROR, ON_LOAD, ON_LOAD_END, ON_LOAD_START, ON_PROGRESS})
|
||||
|
|
Loading…
Reference in New Issue