背景
开发一款简单的闪光灯应用。
- 可以通过某个键去控制闪光灯开关(公司是搞Android 设备的,系统定制,因此有权限监听键值)
- 在闪灯灯页面有个图标用来控制闪光灯开关
闪光灯应用只有一个界面,界面中会显示当前是开或者关。
但是我发现有时候界面中闪光灯状态始终是灰色。
代码
写了一个用于控制闪光灯开启的单例类,FlashLightUtil
.
package com.seuic.flashlight.util;
import android.content.Context;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.util.Log;
import com.seuic.flashlight.MyApplication;
import java.lang.ref.WeakReference;
public class FlashLightUtil {
private volatile static FlashLightUtil instance;
private boolean isFlashLightOn = false;
private Context mContext;
private WeakReference<FlashLightStatusListener> flashLightStatusListener = null;
private FlashLightUtil(Context context) {
mContext = context;
}
public static FlashLightUtil getInstance() {
if (instance == null) {
synchronized (FlashLightUtil.class) {
if (null == instance) {
instance = new FlashLightUtil(MyApplication.mApplication);
}
}
}
return instance;
}
private static final String TAG = "FlashLightUtil";
public boolean isFlashLightOn() {
return isFlashLightOn;
}
public synchronized void toggleFlashLight() {
isFlashLightOn = !isFlashLightOn;
changeFlashLight(isFlashLightOn);
}
public void changeFlashLight(boolean open) {
try {
//获取CameraManager
CameraManager mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
//获取当前手机所有摄像头设备ID
String[] ids = mCameraManager.getCameraIdList();
for (String id : ids) {
CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id);
//查询该摄像头组件是否包含闪光灯
Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
if (flashAvailable != null && flashAvailable
&& lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
notifyChange(open);
//打开或关闭手电筒
mCameraManager.setTorchMode(id, open);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean supportFlashLight() {
boolean isSupport = false;
try {
//获取CameraManager
CameraManager mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
//获取当前手机所有摄像头设备ID
String[] ids = mCameraManager.getCameraIdList();
for (String id : ids) {
CameraCharacteristics c = mCameraManager.getCameraCharacteristics(id);
//查询该摄像头组件是否包含闪光灯
Boolean flashAvailable = c.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
Integer lensFacing = c.get(CameraCharacteristics.LENS_FACING);
if (flashAvailable != null && flashAvailable
&& lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
//打开或关闭手电筒
isSupport = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return isSupport;
}
public void setFlashLightStatusListener(FlashLightStatusListener flashLightStatusListener) {
this.flashLightStatusListener = new WeakReference<>(flashLightStatusListener);
}
private void notifyChange(boolean open) {
if (this.flashLightStatusListener != null) {
FlashLightStatusListener f = flashLightStatusListener.get();
}
}
public interface FlashLightStatusListener {
void onStatusChange(boolean isOpen);
}
}
复制代码
然后一个MainActivity.kt
代码如下:
package com.seuic.flashlight
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ImageButton
import com.seuic.flashlight.service.PptService
import com.seuic.flashlight.util.FlashLightUtil
class MainActivity : AppCompatActivity() {
companion object{
private const val TAG = "MainActivity"
}
private val flashLightUtil by lazy { FlashLightUtil.getInstance() }
private val ivControl by lazy { findViewById<ImageButton>(R.id.iv_control) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ivControl.setOnClickListener {
flashLightUtil.toggleFlashLight()
}
flashLightUtil.setFlashLightStatusListener { isOpen ->
if (isOpen) {
ivControl.setBackgroundResource(R.drawable.ic_flash_light_open)
} else {
ivControl.setBackgroundResource(R.drawable.ic_flash_light_colse)
}
}
startService(Intent(this.application, PptService::class.java))
}
override fun onResume() {
super.onResume()
if (flashLightUtil.isFlashLightOn) {
ivControl.setBackgroundResource(R.drawable.ic_flash_light_open)
} else {
ivControl.setBackgroundResource(R.drawable.ic_flash_light_colse)
}
}
}
复制代码
我发现代码始终没有走到 ivControl.setBackgroundResource
这个地方。
原因
代码没走到这个地方的原因是因为setFlashLightStatusListener
传入的对象是没有强引用的,因此flashLightStatusListener.get();
获取的是一个null对象。一开始之所以使用WeakReference
来保存flashLightStatusListener
对象是防止强引用了MainActivity
的对象,影响MainActivity
的回收(MainActivity退出后仍然有一个服务活在后台,持有FlashLightUtil的对象),但是实际上我传入的是一个局部对象而不是MainActivity
的属性,此局部的FlashLightStatusListener
对象由于没有强引用,因此就被回收了。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END