我正在使用 Mobile Vision API 来检测前置摄像头上的人脸。我使用了 Google 的 FaceTracker 演示,但我需要在 Fragment 中使用它。它正在工作,但是当我尝试旋转屏幕时,应用程序崩溃并出现异常RuntimeException: Fail to connect to camera service
。
片段代码:
class EyeTrackerFragment : Fragment(), AnkoLogger {
private var cameraSource: CameraSource? = null
private lateinit var cameraSourcePreview: CameraSourcePreview
private lateinit var graphicOverlay: GraphicOverlay
private var callback: OnEyeContextUpdatedListener? = null
companion object {
// google play services error code
private val RC_HANDLE_GMS = 9001
// permission request codes need to be < 256
private val RC_HANDLE_CAMERA_PERM = 2
}
override fun onAttach(context: Context?) {
super.onAttach(context)
try {
callback = activity as OnEyeContextUpdatedListener
} catch (e: ClassCastException) {
throw ClassCastException("${activity} must implement OnEyeContextUpdatedListener")
}
}
/**
* Restarts the camera.
*/
override fun onResume() {
super.onResume()
startCameraSource()
}
/**
* Stops the camera.
*/
override fun onPause() {
super.onPause()
cameraSourcePreview.stop()
}
/**
* Releases the resources associated with the camera source, the associated detector, and the
* rest of the processing pipeline.
*/
override fun onDestroy() {
super.onDestroy()
cameraSource?.release()
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? =
inflater!!.inflate(R.layout.fragment_face_tracker, container, false)
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
cameraSourcePreview = getView()!!.findViewById<View>(R.id.preview) as CameraSourcePreview
graphicOverlay = getView()!!.findViewById<View>(R.id.faceOverlay) as GraphicOverlay
if (ActivityCompat.checkSelfPermission(context.applicationContext, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
createCameraSource()
} else {
requestCameraPermission()
}
}
/**
* Handles the requesting of the camera permission. This includes
* showing a "Toast" message of why the permission is needed then
* sending the request.
*/
private fun requestCameraPermission() {
warn("Camera permission is not granted. Requesting permission")
val permissions = arrayOf(Manifest.permission.CAMERA)
if (!ActivityCompat.shouldShowRequestPermissionRationale(activity,
Manifest.permission.CAMERA)) {
ActivityCompat.requestPermissions(activity, permissions, RC_HANDLE_CAMERA_PERM)
return
}
Toast.makeText(context.applicationContext, "Give me permissions", Toast.LENGTH_LONG).show()
}
private fun createCameraSource() {
val detector = FaceDetector.Builder(context.applicationContext)
.setClassificationType(FaceDetector.ALL_CLASSIFICATIONS)
.setProminentFaceOnly(true)
.setTrackingEnabled(true)
.setMode(FaceDetector.ACCURATE_MODE)
.build()
val faceTracker = GraphicFaceTracker(graphicOverlay, callback, context)
val faceProcessor = LargestFaceFocusingProcessor(detector, faceTracker)
detector.setProcessor(faceProcessor)
if (!detector.isOperational) {
longToast("Face detector dependencies are not yet available.")
}
cameraSource = CameraSource.Builder(context, detector)
.setRequestedPreviewSize(640, 480)
.setFacing(CameraSource.CAMERA_FACING_FRONT)
.setRequestedFps(30.0f)
.build()
}
private fun startCameraSource() {
// check that the device has play services available.
val code = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
context.applicationContext)
if (code != ConnectionResult.SUCCESS) {
val dlg = GoogleApiAvailability.getInstance().getErrorDialog(activity, code, RC_HANDLE_GMS)
dlg.show()
}
if (cameraSource != null) {
try {
cameraSourcePreview.start(cameraSource!!, graphicOverlay)
} catch (e: IOException) {
error("Unable to start camera source.", e)
cameraSource!!.release()
cameraSource = null
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
if (requestCode != RC_HANDLE_CAMERA_PERM) {
debug("Got unexpected permission result: $requestCode")
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
return
}
if (grantResults.size != 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
debug("Camera permission granted - initialize the camera source")
createCameraSource()
return
}
error("Permission not granted: results len = ${grantResults.size}. Result code = ${if (grantResults.isNotEmpty()) grantResults[0] else "(empty)"}")
val builder = AlertDialog.Builder(context)
builder.setTitle("Face Tracker sample")
.setMessage("Have no camera permission")
.setPositiveButton("Ok", { _, _ -> activity.finish() })
.show()
}
}
根据活动代码。它只在 onCreate 方法中附加上一个片段,然后不做任何事情。
我猜想在某些情况下没有释放相机实例,但它的完成方式与 Activity 中的相同。Fragment 中是否有任何特殊行为需要与活动相比需要额外的操作?
完整的异常日志:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.eyetracker.android.demo, PID: 22631
java.lang.RuntimeException: Fail to connect to camera service
at android.hardware.Camera.<init>(Camera.java:520)
at android.hardware.Camera.open(Camera.java:361)
at com.google.android.gms.vision.CameraSource.zzchq(Unknown Source)
at com.google.android.gms.vision.CameraSource.start(Unknown Source)
at com.eyetracker.android.camera.CameraSourcePreview.startIfReady(CameraSourcePreview.kt:82)
at com.eyetracker.android.camera.CameraSourcePreview.access$startIfReady(CameraSourcePreview.kt:18)
at com.eyetracker.android.camera.CameraSourcePreview$SurfaceCallback.surfaceCreated(CameraSourcePreview.kt:104)
at android.view.SurfaceView.updateWindow(SurfaceView.java:580)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:176)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:948)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1974)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1065)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5901)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
at android.view.Choreographer.doCallbacks(Choreographer.java:580)
at android.view.Choreographer.doFrame(Choreographer.java:550)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5389)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)