Какой поток я должен использовать для вызова вызовов uiManager внутри собственного встроенного компонента пользовательского интерфейса?
Я создаю собственный компонент пользовательского интерфейса для Android, который использует представление, которое расширяет ReactRootView
,
На конструктор моего взгляда (названный SyncRootView
) если я проверю нить, я получаю Thread curThread = Thread.current(); // main
так что мы в главной теме.
Проблема в том, что если я пытаюсь запустить какой-либо uiManager
звонки (например uiManager.createView
Я получаю эту ошибку:
FATAL EXCEPTION: main
Process: com.rnexample, PID: 16424
java.lang.AssertionError
at com.facebook.infer.annotation.Assertions.assertCondition(Assertions.java:66)
at com.facebook.react.common.SingleThreadAsserter.assertNow(SingleThreadAsserter.java:27)
at com.facebook.react.uimanager.ShadowNodeRegistry.getNode(ShadowNodeRegistry.java:67)
at com.facebook.react.uimanager.UIImplementation.createView(UIImplementation.java:278)
at com.facebook.react.uimanager.UIManagerModule.createView(UIManagerModule.java:364)
at com.sudoplz.rnsynchronouslistmanager.Sync.SyncRootView$3.run(SyncRootView.java:177)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:31)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
Таким образом, в основном проблема заключается в том, что класс с именем SingleThreadAsserter является частью react-native
что я даже не уверен, почему это там. Это mThread
значение установлено в native_module_thread...
поэтому я получаю AssertionError
потому что я в главной теме.
Если я попытаюсь запустить те uiManager
вызовы в потоке native_module (используя ctx.runOnNativeModulesQueueThread(myRunnable)
), сначала кажется, что работает, но позже (я думаю, как только инициализация модуля закончится??) я получаю
Tried to enqueue runnable on already finished thread: 'native_modules... dropping Runnable.
02-21 01:55:36.415 17126-17126/com.rnexample W/MessageQueue: Handler (com.facebook.react.bridge.queue.MessageQueueThreadHandler) {bda653f} sending message to a Handler on a dead thread
java.lang.IllegalStateException: Handler (com.facebook.react.bridge.queue.MessageQueueThreadHandler) {bda653f} sending message to a Handler on a dead thread
at android.os.MessageQueue.enqueueMessage(MessageQueue.java:543)
at android.os.Handler.enqueueMessage(Handler.java:643)
at android.os.Handler.sendMessageAtTime(Handler.java:612)
at android.os.Handler.sendMessageDelayed(Handler.java:582)
at android.os.Handler.post(Handler.java:338)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl.runOnQueue(MessageQueueThreadImpl.java:61)
at com.facebook.react.bridge.ReactContext.runOnNativeModulesQueueThread(ReactContext.java:287)
at com.sudoplz.rnsynchronouslistmanager.Sync.SyncRootView.dispatchInUIThread(SyncRootView.java:516)
at com.sudoplz.rnsynchronouslistmanager.Sync.SyncRootView.runApplication(SyncRootView.java:188)
at com.sudoplz.rnsynchronouslistmanager.Sync.SyncRootView.<init>(SyncRootView.java:97)
at com.sudoplz.rnsynchronouslistmanager.Sync.SyncRootView.<init>(SyncRootView.java:61)
at com.sudoplz.rnsynchronouslistmanager.List.SPView.<init>(SPView.java:20)
at com.sudoplz.rnsynchronouslistmanager.SynchronousListManager.createViewInstance(SynchronousListManager.java:37)
at com.sudoplz.rnsynchronouslistmanager.SynchronousListManager.createViewInstance(SynchronousListManager.java:19)
at com.facebook.react.uimanager.ViewManager.createView(ViewManager.java:44)
at com.facebook.react.uimanager.NativeViewHierarchyManager.createView(NativeViewHierarchyManager.java:224)
at com.facebook.react.uimanager.UIViewOperationQueue$CreateViewOperation.execute(UIViewOperationQueue.java:153)
at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:813)
at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:926)
at com.facebook.react.uimanager.UIViewOperationQueue.access$2100(UIViewOperationQueue.java:47)
at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:986)
at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:31)
at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:136)
at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:107)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:872)
at android.view.Choreographer.doCallbacks(Choreographer.java:686)
at android.view.Choreographer.doFrame(Choreographer.java:618)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
есть идеи?
1 ответ
Я закончил тем, что сделал это:
на конструкторе моего ReactRootView
Я сделал:
nativeModulesThread = (MessageQueueThreadImpl) ctx.getCatalystInstance().getReactQueueConfiguration().getNativeModulesQueueThread();
где ctx это ReactContext
доступны для каждого пользовательского интерфейса.
Затем я создал этот метод:
protected void dispatchInAppropriateThread(Runnable runnable) {
if (runnable == null) {
return;
}
if (nativeModulesThread.getLooper().getThread().isAlive()) {
ctx.runOnNativeModulesQueueThread(runnable);
} else {
this.post(runnable);
}
}
так что теперь, когда мне нужно запустить работающий, я делаю:
dispatchInAppropriateThread(new Runnable() {
@Override
public void run() {
// do cool stuff
}
});