Camera有哪几种使用场景?
- 调用系统相机
- 使用Camera API
使用Camera大致的流程
1、调用系统的相机实现拍照/存储/显示
AndroidManifest.xml中写上需要的权限 注意:android6.0之后需要动态申请权限
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/id_btn"
android:layout_width="match_parent"
android:text="拍照"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/id_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
主要代码: MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/pic/pic.jpg";
private static final int REQ_CODE = 1001;
private ImageView mImageView;
private Button mBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = findViewById(R.id.id_iv);
mBtn = findViewById(R.id.id_btn);
initEvent();
initPhotoError();
}
private void initEvent() {
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
requestPermission();
}
});
}
/**
* 调用系统相机拍照
*
* @param
*/
public void systemCamera() {
Intent intent = new Intent();
//添加动作和策略
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
//在内存卡中创建文件夹保存 拍完的照片
File file = new File(PATH);
//判断文件是否存在 存在删除
if (file.exists()) {
file.delete();
}
//将文件转成Uri
Uri uri = Uri.fromFile(file);
//将拍完照的结果 放到定义好的uri中
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
//因为拍照的保存是异步的,所以需要利用这个start方法拿最终的结果
startActivityForResult(intent, REQ_CODE);
}
/**
* 解决 报错 exposed beyond app through ClipData.Item.getUri()
*/
private void initPhotoError() {
// android 7.0系统解决拍照的问题
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
}
//当异步数据存储好后,重写这个方法拿返回完成的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQ_CODE) {
//拿到存储的好的照片
File file = new File(PATH);
if (file.exists()) {
//设置给图片
//Uri.fromFile(file)是file:///storage/emulated/0/pic/pic.jpg
//第二次覆盖的时候,先让它设置为null
mImageView.setImageURI(null);
mImageView.setImageURI(Uri.fromFile(file));
}
}
}
/**
* android 6.0 动态申请权限
*/
private void requestPermission() {
//如果读内存的权限没有被申请
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
//则申请
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQ_CODE);
}
//如果相机的权限没有被申请
else if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
//则申请
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQ_CODE);
} else {
//才能调用拍照的方法
systemCamera();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQ_CODE) {
//如果权限被授予了
if (grantResults.length > 0) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
//如果第一个权限还没有申请
Toast.makeText(this, "需要读取内存的权限", Toast.LENGTH_SHORT).show();
} else if (grantResults[1] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "需要开启相机的权限", Toast.LENGTH_SHORT).show();
} else {//两个都申请了
//才能调用拍照的方法
systemCamera();
}
}
return;
}
}
}
2、使用Camera API
Camera API的使用
- 1. 有哪些API?
- 2. 如何使用?
- 3. 学会学习API的方法
效果:
- 点击CAMERA API 创建camera视图 (surfaceView 装 Camera 来显示)
- 点击 TAKE PHOTO 实现 camera的拍照功能 (Camera的方法、还有更多的参数设置)
- 点击 “拍照” 是调用系统拍照的方法
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/id_btn_system"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="拍照" />
<Button
android:id="@+id/id_btn_api"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Camera API" />
<Button
android:id="@+id/id_btn_take_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Take photo" />
<FrameLayout
android:id="@+id/CameraLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</FrameLayout>
<ImageView
android:id="@+id/id_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
在之前的代码基础下,添加使用Camera API 的方式调用相机 和拍照
java 代码
- 点击CAMERA API 创建camera视图 (surfaceView 装 Camera 来显示)
- 点击 TAKE PHOTO 实现 camera的拍照功能 (Camera的方法、还有更多的参数设置)
- 注意是这个 hardware包下的 Camera import android.hardware.Camera;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
public static final String PATH = Environment.getExternalStorageDirectory().getPath() + "/pic/pic.jpg";
private static final int REQ_CODE = 1001;
private ImageView mImageView;
//调用Camera 时API弹出的拍照视图
private FrameLayout mCameraLayout;
private volatile int mStatus = 0;
private Button mBtn_System, mBtn_API, mBtn_take_photo;
private Camera mCamera;
private CameraView mCameraView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
mImageView = findViewById(R.id.id_iv);
mCameraLayout = findViewById(R.id.CameraLayout);
mBtn_System = findViewById(R.id.id_btn_system);
mBtn_API = findViewById(R.id.id_btn_api);
mBtn_take_photo = findViewById(R.id.id_btn_take_photo);
mBtn_take_photo.setOnClickListener(this);
mBtn_System.setOnClickListener(this);
mBtn_API.setOnClickListener(this);
initPhotoError();
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.id_btn_system:
mStatus = 0;
break;
case R.id.id_btn_api:
mStatus = 1;
break;
case R.id.id_btn_take_photo:
mStatus = 2;
break;
}
//权限申请
requestPermission();
}
/**
* 调用系统相机拍照
*
* @param
*/
public void systemCamera() {
/**
* 因为Camera API 和 调用系统的方法都是调用系统的相机
* 所已可能会造成一些冲突
*/
if (mImageView != null) {
//如果不为空,先释放 避免占用冲突
mCameraView.release();
}
Intent intent = new Intent();
//添加动作和策略
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
//在内存卡中创建文件夹保存 拍完的照片
File file = new File(PATH);
//判断文件是否存在 存在删除
if (file.exists()) {
file.delete();
}
//将文件转成Uri
Uri uri = Uri.fromFile(file);
//将拍完照的结果 放到定义好的uri中
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
//因为拍照的保存是异步的,所以需要利用这个start方法拿最终的结果
startActivityForResult(intent, REQ_CODE);
}
/**
* 使用Camera API 时的方法
*/
private void cameraAPI() {
//1.创建一个camera视图
//2.将camera视图添加到cameraLayout中
//做一下camera的设置
mCamera = getCamera();
mCameraView = new CameraView(this, mCamera);
//将CameraView添加到FragmentLayout中
mCameraLayout.addView(mCameraView);
//将拍完的照片旋转角度保存 因为不旋转不是水平的一个状态
Camera.Parameters parameters = mCamera.getParameters();
parameters.setRotation(90);
mCamera.setParameters(parameters);
}
/**
* Camera API 的拍照按钮
*/
private void takePhoto() {
//3.点击按钮,并保存到存储里面
if (mCamera != null) {
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File file = new File(PATH);
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
//将拍照完之后的数据 这里是byte[] 类型的写入到之前的文件中
fileOutputStream.write(data);
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
/**
* 得到Camera
*
* @return
*/
public Camera getCamera() {
Camera camera = null;
//打开相机
try {
camera = Camera.open();
} catch (Exception e) {
e.printStackTrace();
//错误提示
}
return camera;
}
//新建内部类做camera的视图
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
Camera mCamera;
private final SurfaceHolder mHolder;
public CameraView(Context context, Camera camera) {
super(context);
mCamera = camera;
//surfaceView的监听器
mHolder = getHolder();
mHolder.addCallback(this);
}
//SurfaceView的创建
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera != null) {
//把Camera的显示设置为当前的SurfaceHolder
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
//设置相机显示的角度
mCamera.setDisplayOrientation(90);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//视图变更
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (mHolder.getSurface() == null) {
return;
}
try {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} else {
//提示用户
}
} catch (IOException e) {
e.printStackTrace();
}
}
//销毁
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
release();
}
/**
* 释放Camera
*/
public void release() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
private void Method() {
switch (mStatus) {
case 0:
systemCamera();
break;
case 1:
cameraAPI();
break;
case 2:
takePhoto();
break;
}
}
/**
* 解决 报错 exposed beyond app through ClipData.Item.getUri()
*/
private void initPhotoError() {
// android 7.0系统解决拍照的问题
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
builder.detectFileUriExposure();
}
//当异步数据存储好后,重写这个方法拿返回完成的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQ_CODE) {
//拿到存储的好的照片
File file = new File(PATH);
if (file.exists()) {
//设置给图片
//Uri.fromFile(file)是file:///storage/emulated/0/pic/pic.jpg
//第二次覆盖的时候,先让它设置为null
mImageView.setImageURI(null);
mImageView.setImageURI(Uri.fromFile(file));
}
}
}
/**
* android 6.0 动态申请权限
*/
private void requestPermission() {
//如果相机的权限没有被申请
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
//则申请
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQ_CODE);
} else {
//如果申请了执行相应的方法
Method();
Log.e("TAG", mStatus + "");
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQ_CODE) {
//如果权限被授予了
if (grantResults.length > 0) {
if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
//如果第一个权限还没有申请
Toast.makeText(this, "需要开启相机的权限", Toast.LENGTH_SHORT).show();
} else {//申请了
//根据状态调用相应的方法
Method();
}
}
return;
}
}
@Override
protected void onPause() {
super.onPause();
if (mCameraView != null) {
mCameraView.release();
}
}
}
Camera API 5.0 以前的(目前使用)
Camera API2 5.0以后的
Extend拓展:
- 1. 与Camera相类似的硬件Audio, Recorder, Video等
- 2. 关联知识点:文件上传,权限判断等