Android使用相机
有两种方式:
- 使用已经存在的Apps
- 构建自己的相机App
基础步骤
安卓系统提供了
android.hardware.caemra2
API和camera intent去拍摄图片或者视频
以下是相关的类:
-
android.hardware.camera2
这个包提供api去控制相机设备。可以通过它使用拍照片和视频。
-
Camera
这个类提供已经过时的控制相机设备的api。
-
SurfaceView
这个类被用于提供给用户一个实时的相机预览。
-
MediaRecorder
这个类被用来从相机记录视频。
-
Intent
MediaStroe.ACTION_IMAGE_CAPTURE
和MediaStore.ACTION_VIDEO_CAPTURE
能被用来拍图片和视频,通过直接使用系统的相机。
权限说明
<uses-permission android:name="android.permission.CAMERA" />
使用相机就需要生命该权限
<uses-feature android:name="android.hardware.camera2" />
这个声明是为了让GooglePlay在展示App时,避免不支持相机的设备。
还有:(如果需要)
- 储存权限
- 录制权限
- 定位权限
建立一个自己的相机
通常步骤:
- 检测和访问相机
- 创建一个预览相机视图的类,继承SurfaceView
- 建立一个预览布局
- 为拍照设置监听
- 拍照并且保存到文件
- 释放相机
检测和访问相机
检查设备是否有相机
private boolean checkCameraHardware(Context context) {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
获取相机实例
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
}
return camera;
}
在Android2.3以上版本,可以通过使用
Camera.open(int)
去得到前置或者后置相机
创建实时预览View
通过继承SurfaceView
能够实时显示从相机返回的数据
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
//添加一个SurfaceHolder.CallBack,能够在SurfaceView被创建和销毁时通知我们
mHolder = getHolder();
mHolder.addCallback(this);
//声明Surface使用的数据由其他数据提供
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//Surface已经被创建,现在让相机开始预览
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.e("TAG", e.getMessage());
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//如果预览窗口被改变和旋转
//确保停止之前,重新确定大小和格式
if (mHolder.getSurface() == null) {
//预览视图不存在,则结束
return;
}
//在发生改变之前,停止预览
try {
mCamera.stopPreview();
} catch (Exception e) {
}
//设置预览的尺寸和旋转
holder.setFixedSize(width, height);
holder.setFormat(format);
//开始预览伴随新的设置
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
创建布局
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/button_capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="20dp"
android:text="Capture" />
</FrameLayout>
绑定实时预览到Activity
public class MainActivity extends AppCompatActivity {
private Camera mCamera;
private CameraPreview mCameraPreview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!checkCameraHardware(this)) {
Toast.makeText(this, "No Camera", Toast.LENGTH_SHORT).show();
finish();
return;
}
mCamera = getCameraInstance();
mCameraPreview = new CameraPreview(this, mCamera);
FrameLayout preView = (FrameLayout) findViewById(R.id.camera_preview);
preView.addView(mCameraPreview);
}
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
} catch (Exception e) {
Log.e("TAG", e.getMessage());
}
return camera;
}
private boolean checkCameraHardware(Context context) {
return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
}
@Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
}
拍照并储存
private Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File picFile = getOutputFile(MEDIA_TYPE_IMAGE);
if (picFile == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(picFile);
fos.write(data);
fos.close();
Toast.makeText(MainActivity.this, "take photo", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
Log.i("TAG", "file not found");
} catch (IOException e) {
Log.i("TAG", e.getMessage());
}
}
};
private File getOutputFile(int type) {
//为了安全,应先检查SD卡是否存在
if (Environment.getExternalStorageState().equals(Environment.MEDIA_UNMOUNTED)) {
return null;
}
File mediaDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"CAMERA LEARN");
if (!mediaDir.exists()) {
if (!mediaDir.mkdir()) {
Log.i("TAG", "make dir failed");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else if (type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
findViewById(R.id.button_capture).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCamera.takePicture(null, null, pictureCallback);
}
});
现在之后能成功拍照保存,但是相机实时显示的方向有问题,明晚继续学习。_