Android Kotlin 悬浮View/Service中无法启动相机预览问题求助
核心问题排查与修复方案
代码存在的问题:
- ViewBinding未初始化:你声明了
lateinit var binding: OverlayLayoutBinding但没有做绑定操作,inflate出mFloatingView后需要补充binding = OverlayLayoutBinding.bind(mFloatingView),否则访问binding.viewFinder会直接抛出异常,相机预览无法关联到对应控件。 - 生命周期所有者参数非法:你定义的全局
context变量默认值为null,将其强转为LifecycleOwner传入CameraX绑定逻辑必然崩溃。同时普通Service没有实现LifecycleOwner接口,无法直接为CameraX提供生命周期支持,需要改为继承LifecycleService。 - 重复初始化相机:onCreate中连续两次调用
startCamera,会导致相机资源抢占,触发初始化失败。 - 前台服务逻辑缺失:
startMyOwnForeground方法未实现,Android 8.0及以上系统要求前台服务必须创建合法通知渠道并展示有效通知,否则服务会被系统直接杀死。 - 权限配置不全:该功能需要悬浮窗权限、相机权限、Android 12+的相机前台服务权限,缺少任意权限都会导致功能失效。
修改后的核心代码:
// 继承LifecycleService获取生命周期能力 class FloatingViewService : LifecycleService() { private var mWindowManager: WindowManager? = null private lateinit var binding: OverlayLayoutBinding private var imageCapture: ImageCapture? = null private var mFloatingView: View? = null private var params: WindowManager.LayoutParams? = null override fun onBind(intent: Intent?): IBinder? { super.onBind(intent) return null } @SuppressLint("ClickableViewAccessibility") override fun onCreate() { super.onCreate() // 补全前台服务逻辑 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channelId = "floating_camera_channel" val channel = NotificationChannel(channelId, "悬浮相机服务", NotificationManager.IMPORTANCE_LOW) getSystemService(NotificationManager::class.java).createNotificationChannel(channel) val notification = Notification.Builder(this, channelId) .setContentTitle("悬浮相机运行中") .setSmallIcon(R.drawable.ic_launcher_foreground) .build() startForeground(1, notification) } else { startForeground(1, Notification()) } // 加载布局并初始化binding mFloatingView = LayoutInflater.from(this).inflate(R.layout.overlay_layout, null) binding = OverlayLayoutBinding.bind(mFloatingView!!) val LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY params = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, LAYOUT_FLAG, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT ) mWindowManager = getSystemService(WINDOW_SERVICE) as WindowManager mWindowManager!!.addView(mFloatingView, params) // 只调用一次相机初始化,且在binding初始化之后执行 startCamera() } private fun startCamera() { val cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener({ val cameraProvider = cameraProviderFuture.get() val preview = Preview.Builder() .build() .also { it.setSurfaceProvider(binding.viewFinder.surfaceProvider) } imageCapture = ImageCapture.Builder().build() val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA try { cameraProvider.unbindAll() // 直接传当前LifecycleService作为生命周期所有者 cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture) } catch (e: Exception) { Log.d(Constants.TAG, "相机启动失败", e) } }, ContextCompat.getMainExecutor(this)) } }
清单文件配置补充:
<!-- 权限声明 --> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" /> <!-- 服务注册 --> <service android:name=".FloatingViewService" android:foregroundServiceType="camera" android:exported="false" />
额外注意事项
需要提前向用户动态申请悬浮窗权限和相机权限,用户同意后再启动服务。
内容的提问来源于stack exchange,提问作者AndroidAficionado
相关产品推荐
相关产品推荐

