You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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中添加相机权限:
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.flash" />
    
    Android 6.0及以上版本需要动态申请CAMERA权限,否则会抛出CameraAccessException。
  • 生命周期管理:在onPause、onDestroy时停止循环并关闭手电筒,避免后台持续占用相机资源和耗电。
  • 避免主线程阻塞:绝对不要在主线程中使用while(true)这类死循环,会导致ANR(应用无响应)。

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:43:22