Android中使用Kotlin实现手电筒开关无限循环的问题
解决Android Kotlin手电筒无限交替开关问题
原代码问题分析
- 主线程中使用
while(true)会直接阻塞UI线程,导致Handler.postDelayed的任务根本无法被调度执行,手电筒一直保持初始开启状态。 openFlashLight和closeFlashLight逻辑高度重复,且没有实现循环触发的机制,去掉while(true)后只能执行一次开关动作。
修正方案
使用递归式Handler延迟任务或Kotlin协程实现无限循环,同时简化手电筒控制逻辑,还要处理生命周期避免资源泄漏:
方案1:基于Handler实现
package com.example.flashlight import android.content.Context import android.hardware.camera2.CameraAccessException import android.hardware.camera2.CameraManager import android.os.Bundle import android.os.Handler import android.os.Looper import androidx.appcompat.app.AppCompatActivity class MainActivity : AppCompatActivity() { private var flashLightStatus: Boolean = false private lateinit var cameraManager: CameraManager private lateinit var cameraId: String private val mainHandler = Handler(Looper.getMainLooper()) private val toggleRunnable = object : Runnable { override fun run() { toggleFlashlight() // 5秒后再次执行自身,实现无限循环 mainHandler.postDelayed(this, 5000) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化相机管理器和相机ID cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager cameraId = cameraManager.cameraIdList[0] // 初始打开手电筒,启动循环 toggleFlashlight() mainHandler.postDelayed(toggleRunnable, 5000) } private fun toggleFlashlight() { flashLightStatus = !flashLightStatus try { cameraManager.setTorchMode(cameraId, flashLightStatus) } catch (e: CameraAccessException) { e.printStackTrace() } } override fun onPause() { super.onPause() // 暂停时关闭手电筒并移除任务,避免后台耗电 mainHandler.removeCallbacks(toggleRunnable) if (flashLightStatus) { try { cameraManager.setTorchMode(cameraId, false) } catch (e: CameraAccessException) { e.printStackTrace() } } } }
方案2:基于Kotlin协程实现(更简洁)
package com.example.flashlight import android.content.Context import android.hardware.camera2.CameraAccessException import android.hardware.camera2.CameraManager import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext class MainActivity : AppCompatActivity() { private var flashLightStatus: Boolean = false private lateinit var cameraManager: CameraManager private lateinit var cameraId: String private val mainScope = CoroutineScope(Dispatchers.Main) private var isLoopRunning = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager cameraId = cameraManager.cameraIdList[0] startFlashLoop() } private fun startFlashLoop() { isLoopRunning = true mainScope.launch { // 初始打开手电筒 toggleFlashlight() while (isLoopRunning) { delay(5000) toggleFlashlight() } } } private suspend fun toggleFlashlight() { flashLightStatus = !flashLightStatus // 切换手电筒需在主线程执行(CameraManager要求) withContext(Dispatchers.Main) { try { cameraManager.setTorchMode(cameraId, flashLightStatus) } catch (e: CameraAccessException) { e.printStackTrace() } } } override fun onPause() { super.onPause() isLoopRunning = false if (flashLightStatus) { try { cameraManager.setTorchMode(cameraId, false) } catch (e: CameraAccessException) { e.printStackTrace() } } } }
关键注意事项
- 权限配置:在
AndroidManifest.xml中添加相机权限:
Android 6.0及以上版本需要动态申请<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.flash" />CAMERA权限,否则会抛出CameraAccessException。 - 生命周期管理:在
onPause、onDestroy时停止循环并关闭手电筒,避免后台持续占用相机资源和耗电。 - 避免主线程阻塞:绝对不要在主线程中使用
while(true)这类死循环,会导致ANR(应用无响应)。
内容的提问来源于stack exchange,提问作者Daniel Lip
相关产品推荐
相关产品推荐

