背景
开发一款简单的闪光灯应用。
- 可以通过某个键去控制闪光灯开关(公司是搞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();
f.onStatusChange(open);
}
}
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, KeyService::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)
}
}
}
另外还有一个监听自定义键值的服务(因为是系统应用,不需要使用前台服务保活)
class KeyService : Service(){
companion object {
private const val TAG = "PptService"
private const val KEY_MONITORING = "252"
}
private val flashLightUtil by lazy { FlashLightUtil.getInstance() }
private val mScanKeyService by lazy { ScanKeyService.getInstance() }
private val mCallback: IKeyEventCallback = object : IKeyEventCallback.Stub() {
@Throws(RemoteException::class)
override fun onKeyDown(keyCode: Int) {
flashLightUtil.toggleFlashLight()
}
@Throws(RemoteException::class)
override fun onKeyUp(keyCode: Int) = Unit
}
override fun onCreate() {
super.onCreate()
Log.i(TAG, "onCreate: ")
mScanKeyService.registerCallback(
mCallback,
KEY_MONITORING
)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.i(TAG, "onStartCommand: ")
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onDestroy() {
super.onDestroy()
Log.i(TAG, "onDestroy: ")
mScanKeyService.unregisterCallback(mCallback)
}
}
我发现代码始终没有走到 ivControl.setBackgroundResource
这个地方。
原因
代码没走到这个地方的原因是因为setFlashLightStatusListener
传入的对象是没有强引用的,因此flashLightStatusListener.get();
获取的是一个null对象。一开始之所以使用WeakReference
来保存flashLightStatusListener
对象是防止强引用了MainActivity
的对象,影响MainActivity
的回收(MainActivity退出后仍然有一个服务活在后台,持有FlashLightUtil的对象),但是实际上我传入的是一个局部对象而不是MainActivity
的属性,此局部的FlashLightStatusListener
对象由于没有强引用,因此就被回收了。
今天的文章记录一次WeakReference 的错误用法分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16904.html