fix: Fix hot-reload crash caused by Frame Processor Runtime being initialized twice (#258)

* Fix Frame Processor Runtime being initialized twice causing a hot-reload to crash

* Remove unnecessary `HasRegisteredPlugins` singleton

* make non-optional

* `REACT_CLASS` -> `TAG`

* fix nullable
This commit is contained in:
Marc Rousavy 2021-07-07 15:00:32 +02:00 committed by GitHub
parent d3a8b49f9b
commit 2f889f5855
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 24 additions and 31 deletions

View File

@ -113,7 +113,7 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
private var maxZoom: Float = 1f private var maxZoom: Float = 1f
@DoNotStrip @DoNotStrip
private var mHybridData: HybridData? private var mHybridData: HybridData
@Suppress("LiftReturnOrAssignment", "RedundantIf") @Suppress("LiftReturnOrAssignment", "RedundantIf")
internal val fallbackToSnapshot: Boolean internal val fallbackToSnapshot: Boolean
@ -185,7 +185,7 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
} }
fun finalize() { fun finalize() {
mHybridData?.resetNative() mHybridData.resetNative()
} }
private external fun initHybrid(): HybridData private external fun initHybrid(): HybridData
@ -478,7 +478,6 @@ class CameraView(context: Context) : FrameLayout(context), LifecycleOwner {
const val TAG_PERF = "CameraView.performance" const val TAG_PERF = "CameraView.performance"
private val propsThatRequireSessionReconfiguration = arrayListOf("cameraId", "format", "fps", "hdr", "lowLightBoost", "photo", "video", "frameProcessorFps") private val propsThatRequireSessionReconfiguration = arrayListOf("cameraId", "format", "fps", "hdr", "lowLightBoost", "photo", "video", "frameProcessorFps")
private val arrayListOfZoom = arrayListOf("zoom") private val arrayListOfZoom = arrayListOf("zoom")
} }
} }

View File

@ -155,16 +155,16 @@ class CameraViewManager : SimpleViewManager<CameraView>() {
} }
override fun onDropViewInstance(view: CameraView) { override fun onDropViewInstance(view: CameraView) {
Log.d(REACT_CLASS, "onDropViewInstance() called!") Log.d(TAG, "onDropViewInstance() called!")
super.onDropViewInstance(view) super.onDropViewInstance(view)
} }
override fun getName(): String { override fun getName(): String {
return REACT_CLASS return TAG
} }
companion object { companion object {
const val REACT_CLASS = "CameraView" const val TAG = "CameraView"
val cameraViewTransactions: HashMap<CameraView, ArrayList<String>> = HashMap() val cameraViewTransactions: HashMap<CameraView, ArrayList<String>> = HashMap()
} }

View File

@ -25,7 +25,7 @@ import kotlinx.coroutines.guava.await
class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
companion object { companion object {
const val REACT_CLASS = "CameraView" const val TAG = "CameraView"
var RequestCode = 10 var RequestCode = 10
val FrameProcessorThread: ExecutorService = Executors.newSingleThreadExecutor() val FrameProcessorThread: ExecutorService = Executors.newSingleThreadExecutor()
@ -42,6 +42,7 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase
override fun initialize() { override fun initialize() {
super.initialize() super.initialize()
if (frameProcessorManager == null) {
FrameProcessorThread.execute { FrameProcessorThread.execute {
frameProcessorManager = FrameProcessorRuntimeManager(reactApplicationContext) frameProcessorManager = FrameProcessorRuntimeManager(reactApplicationContext)
reactApplicationContext.runOnJSQueueThread { reactApplicationContext.runOnJSQueueThread {
@ -49,14 +50,16 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase
} }
} }
} }
}
override fun onCatalystInstanceDestroy() { override fun onCatalystInstanceDestroy() {
super.onCatalystInstanceDestroy() super.onCatalystInstanceDestroy()
frameProcessorManager?.destroy() frameProcessorManager?.destroy()
frameProcessorManager = null
} }
override fun getName(): String { override fun getName(): String {
return REACT_CLASS return TAG
} }
private fun findCameraView(id: Int): CameraView = reactApplicationContext.currentActivity?.findViewById(id) ?: throw ViewNotFoundError(id) private fun findCameraView(id: Int): CameraView = reactApplicationContext.currentActivity?.findViewById(id) ?: throw ViewNotFoundError(id)
@ -208,7 +211,7 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase
val secondsPerFrame = try { val secondsPerFrame = try {
cameraConfig.getOutputMinFrameDuration(formatId, size) / 1_000_000_000.0 cameraConfig.getOutputMinFrameDuration(formatId, size) / 1_000_000_000.0
} catch (error: Throwable) { } catch (error: Throwable) {
Log.e(REACT_CLASS, "Minimum Frame Duration for MediaRecorder Output cannot be calculated, format \"$formatName\" is not supported.") Log.e(TAG, "Minimum Frame Duration for MediaRecorder Output cannot be calculated, format \"$formatName\" is not supported.")
null null
} }
@ -264,7 +267,7 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase
} }
val difference = System.currentTimeMillis() - startTime val difference = System.currentTimeMillis() - startTime
Log.w(REACT_CLASS, "CameraViewModule::getAvailableCameraDevices took: $difference ms") Log.w(TAG, "CameraViewModule::getAvailableCameraDevices took: $difference ms")
return@withPromise cameraDevices return@withPromise cameraDevices
} }
} }

View File

@ -15,15 +15,7 @@ import java.lang.ref.WeakReference
class FrameProcessorRuntimeManager(context: ReactApplicationContext) { class FrameProcessorRuntimeManager(context: ReactApplicationContext) {
companion object { companion object {
const val TAG = "FrameProcessorRuntime" const val TAG = "FrameProcessorRuntime"
private var HasRegisteredPlugins = false
val Plugins: ArrayList<FrameProcessorPlugin> = ArrayList() val Plugins: ArrayList<FrameProcessorPlugin> = ArrayList()
get() {
if (HasRegisteredPlugins) {
throw Error("Tried to access Frame Processor Plugin list, " +
"but plugins have already been registered (list is frozen now!).")
}
return field
}
init { init {
System.loadLibrary("reanimated") System.loadLibrary("reanimated")
@ -32,15 +24,15 @@ class FrameProcessorRuntimeManager(context: ReactApplicationContext) {
} }
@DoNotStrip @DoNotStrip
private var mHybridData: HybridData? private var mHybridData: HybridData
private var mContext: WeakReference<ReactApplicationContext>? private var mContext: WeakReference<ReactApplicationContext>
private var mScheduler: Scheduler? private var mScheduler: Scheduler
init { init {
val holder = context.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl val holder = context.catalystInstance.jsCallInvokerHolder as CallInvokerHolderImpl
mScheduler = Scheduler(context) mScheduler = Scheduler(context)
mContext = WeakReference(context) mContext = WeakReference(context)
mHybridData = initHybrid(context.javaScriptContextHolder.get(), holder, mScheduler!!) mHybridData = initHybrid(context.javaScriptContextHolder.get(), holder, mScheduler)
initializeRuntime() initializeRuntime()
Log.i(TAG, "Installing Frame Processor Plugins...") Log.i(TAG, "Installing Frame Processor Plugins...")
@ -48,19 +40,18 @@ class FrameProcessorRuntimeManager(context: ReactApplicationContext) {
registerPlugin(plugin) registerPlugin(plugin)
} }
Log.i(TAG, "Successfully installed ${Plugins.count()} Frame Processor Plugins!") Log.i(TAG, "Successfully installed ${Plugins.count()} Frame Processor Plugins!")
HasRegisteredPlugins = true
} }
fun destroy() { fun destroy() {
mScheduler?.deactivate() mScheduler.deactivate()
mHybridData?.resetNative() mHybridData.resetNative()
} }
@DoNotStrip @DoNotStrip
@Keep @Keep
fun findCameraViewById(viewId: Int): CameraView { fun findCameraViewById(viewId: Int): CameraView {
Log.d(TAG, "finding view $viewId...") Log.d(TAG, "finding view $viewId...")
val view = mContext?.get()?.currentActivity?.findViewById<CameraView>(viewId) val view = mContext.get()?.currentActivity?.findViewById<CameraView>(viewId)
Log.d(TAG, "found view $viewId! is null: ${view == null}") Log.d(TAG, "found view $viewId! is null: ${view == null}")
return view ?: throw ViewNotFoundError(viewId) return view ?: throw ViewNotFoundError(viewId)
} }
@ -70,7 +61,7 @@ class FrameProcessorRuntimeManager(context: ReactApplicationContext) {
jsContext: Long, jsContext: Long,
jsCallInvokerHolder: CallInvokerHolderImpl, jsCallInvokerHolder: CallInvokerHolderImpl,
scheduler: Scheduler scheduler: Scheduler
): HybridData? ): HybridData
private external fun initializeRuntime() private external fun initializeRuntime()
private external fun registerPlugin(plugin: FrameProcessorPlugin) private external fun registerPlugin(plugin: FrameProcessorPlugin)