百度google一下现有的关于手电筒(实际上是闪光灯控制)的设计和源代码都有很多。
例如
http://www.oschina.net/code/snippet_107931_17160
http://blog.youkuaiyun.com/pengcheng_liu/article/details/23860679
Camera.Parameters param = mCamera.getParameters();
param.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(param);
mCamera.startPreview();
通过设置Camera的FLASH_MODE参数,可以将闪光灯设置为常亮状态,再用startPreivew()方法打开照相机的预览,就可以成功打开闪光灯。
但实际上这些方法只能适配部分机型,而Google Nexus 5、 HTC 部分机型等手机使用这些代码都不能打开闪光灯。
察看Android开发者文档,在Camera的class overview中可以看到我们忽略掉的部分。
http://developer.android.com/intl/zh-cn/reference/android/hardware/Camera.htmlTo take pictures with this class, use the following steps:
1.Obtain an instance of Camera from open(int).
2.Get existing (default) settings with getParameters().
3.If necessary, modify the returned Camera.Parameters object and call setParameters(Camera.Parameters).
4.If desired, call setDisplayOrientation(int).
5.Important: Pass a fully initialized SurfaceHolder to setPreviewDisplay(SurfaceHolder). Without a surface, the camera will be unable to start the preview.
6.Important: Call startPreview() to start updating the preview surface. Preview must be started before you can take a picture.
7.When you want, call takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback) to capture a photo. Wait for the callbacks to provide the actual image data.
8.After taking a picture, preview display will have stopped. To take more photos, call startPreview() again first.
9.Call stopPreview() to stop updating the preview surface.
10.Important: Call release() to release the camera for use by other applications. Applications should release the camera immediately in onPause() (and re-open() it in onResume()).
看到第五点(important),如果没有在startPreview之前调用setPreviewDisplay。照相机就不会启动预览。
所以问题解决,适用于市面上大部分机型的相机开启,需要在startPreview之前setPreivewDisplay:
Camera.Parameters param = mCamera.getParameters();
param.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(param);
mCamera.setPreviewDisplay(mHolder); //重要!在startPreview要调用
mCamera.startPreview();
为setPreviewDisplay(SurfaceHolder holder) 传入的SurfaceHolder参数需要在setPreviewDisplay前初始化完成:
private WindowManager mWindowManager;
private SurfaceHolder mHolder;
private MySurfaceView mFlashTorchSurface;
private void createSurfaceView() {
if (mFlashTorchSurface != null) {
return;
}
try {
mWindowManager = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE); // 获取WindowManager
// 添加手电筒所需要的SurfaceView
mFlashTorchSurface = new MySurfaceView(mContext);
// 由于会在SurfaceView中进行预览,所以将背景色设置为黑色,使用户看不到
mFlashTorchSurface.setBackgroundColor(Color.BLACK);
WindowManager.LayoutParams mCallViewParams = new WindowManager.LayoutParams(); // 设置LayoutParams(全局变量)相关参数
mCallViewParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
mCallViewParams.format = PixelFormat.RGBA_8888; // 设置透明背景
mCallViewParams.width = 1;
mCallViewParams.height = 1;
mCallViewParams.gravity = Gravity.RIGHT | Gravity.TOP;
mCallViewParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 让当前View失去焦点
mWindowManager.addView(mFlashTorchSurface, mCallViewParams);
} catch (Exception ex) {
ex.printStackTrace();
mFlashTorchSurface = null;
}
}
/**
* 手电筒需要的surface
*/
private class MySurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
public MySurfaceView(Context context) {
super(context);
initHolder();
}
private void initHolder() {
// 注册surfaceCreated、surfaceChanged、surfaceDestroyed回调方法
SurfaceHolder holder = getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 在某些机型上,这一项必须设置
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mHolder = holder;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mHolder = null;
}
}
这样,大部分机型都可以打开手电筒了。
完整的打开关闭方法如下:
public void powerOn() {
//打开手电
initCamera(); //初始化相机
createSurfaceView(); //初始化SurfaceHolder
setLightOn(); //打开手电
}
private void initCamera() {
try {
mCamera = Camera.open();
} catch (Exception e) {
mCamera = null;
}
if (mCamera == null) {
mIsAvailable = false;
} else {
mIsAvailable = true;
}
}
private void setLightOn() {
if (mCamera == null) {
return;
}
try {
// 防止startPreview、setParameters抛出RuntimeException异常导致崩溃
Camera.Parameters param = mCamera.getParameters();
param.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(param);
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
powerOff();
return;
}
}
public void powerOff() {
//关闭手电,手电使用结束后必须释放camera资源,否则会造成内存泄露
setLightOff();//关灯并释放资源
if (mCamera != null) { //保护
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
removeSurfaceView(); //释放SurfaceHodler
}
private void setLightOff() {
if (mCamera == null) {
return;
}
try {
// 防止startPreview、setParameters抛出RuntimeException异常导致崩溃
Camera.Parameters param = mCamera.getParameters();
param.setFlashMode(Parameters.FLASH_MODE_OFF);
mCamera.setParameters(param);
mCamera.stopPreview();
mCamera.release();
} catch (RuntimeException e) {
e.printStackTrace();
mCamera.stopPreview();
mCamera.release();
}
mCamera = null;
mIsLight = false;
}
private void removeSurfaceView() {
if (mFlashTorchSurface != null) {
mWindowManager.removeViewImmediate(mFlashTorchSurface);
mFlashTorchSurface = null;
}
}
当然还要加上相关权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
原地址: http://codesblock.com/blog/?p=56