调用手机摄像头,在当今的众多 App 中都有使用,比如:拍照、扫二维码等。
本篇文章将实现:调用系统相机进行拍照,然后将拍的图片在 App 上显示(显示最后一张图片,和显示之前拍过的所有图片)。
在没接触过 Camera2 之前一定要查文档,官方文档 是首选,而且是最准确的,最新的。
下面就进入进入本篇文章的正题。
先来看一下本文实现的演示图:
示例图片.gif
一、配置文件
调用系统相机就一定要申请相机权限:
<uses-permission android:name="android.permission.CAMERA" />
因为相机权限是危险权限,6.0+ 需要动态申请,这里我只做简易的动态申请:
private static String[] PERMISSION_REQUEST = {
Manifest.permission.CAMERA
};
private static final int INTENT_CAMERA_REQUEST_CODE = 666; // 数字随便写
// 运行时权限请求(简易版)
ActivityCompat.requestPermissions(MainActivity.this, PERMISSION_REQUEST, INTENT_CAMERA_REQUEST_CODE);
二、实现流程
流程: ① 在 App 上点击按钮调用系统相机 ② 拍照 ③ 拍照之后返回到 App ④ 在 App 上显示照片(显示最后一张,显示所有拍照的图片)
重点:
① 调用系统相机
②startActivityForResult
和onActivityResult
的使用
③ 显示所有的图片,我们这里使用RecyclerView
,因为是将所有拍过的图片都添加到列表里,直接将图片添加到列表里显然很不安卓,所以将图片先转换成Base64
二进制流的形式,然后添加到列表里,在显示的时候将Base64
二进制流形式 转换成图片,显示出来。
好的思路捋清了,就开始代码实现。
三、代码实现
① 调用系统相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
我们通过 intent.putExtra()
传值使用 Android 官方 提供的方法:
/**
* Create a File for saving an image
*/
private static File getOutputMediaFile(int type) {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "Camera2Demo");
// Create the storage directory if it does not exist
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("Camera2Demo", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"Camera2Demo_" + timeStamp + ".jpg");
Log.d(TAG, "getOutputMediaFile: " + mediaStorageDir.getPath() + File.separator); // 图片存储的文件夹路径
} else {
return null;
}
return mediaFile;
}
/**
* Create a file Uri for saving an image or video
*/
private static Uri getOutputMediaFileUri(int type) {
return Uri.fromFile(getOutputMediaFile(type));
}
那么调用系统相机的那部分代码就是:
private Uri mFileUri;
按钮.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 跳转到系统相机
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // 拍摄照片
mFileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // 创建文件保存图片
intent.putExtra(MediaStore.EXTRA_OUTPUT, mFileUri); // 设置图片名
startActivityForResult(intent, INTENT_CAMERA_REQUEST_CODE); // 捕获相机拍摄的图片
}
});
这样系统相机就启动了,拍照完之后,将图片保存到已创建的文件夹里,供 App 使用。
② 使用 onActivityResult
将拍的图片返回给 App
我们在上面将图片保存到手机本地文件夹里,那么在读取本地文件夹里的文件的时候,6.0+ 的设备就要动态申请运行时读写权限
private static String[] PERMISSION_REQUEST = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
};
ActivityCompat.requestPermissions(MainActivity.this, PERMISSION_REQUEST, INTENT_CAMERA_REQUEST_CODE);
还要做的一步操作就是检查是否是图片。
/**
* 检查扩展名,得到图片格式的文件
*/
private boolean checkIsImageFile(String fName) {
boolean isImageFile;
// 获取扩展名
String FileEnd = fName.substring(fName.lastIndexOf(".") + 1,
fName.length()).toLowerCase();
if (FileEnd.equals("jpg") || FileEnd.equals("png") || FileEnd.equals("gif")
|| FileEnd.equals("jpeg") || FileEnd.equals("bmp")) {
isImageFile = true;
} else {
isImageFile = false;
}
return isImageFile;
}
好的,我们的 onActivityResult
的结构可以看成是这样:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == INTENT_CAMERA_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
} else if (resultCode == RESULT_CANCELED) {
} else {
}
}
}
让我们来实现 if (resultCode == RESULT_OK) { }
里面的内容
首先是读取本地存储图片的路径,然后将所有的图片添加到列表里
List<String> imagePathList = new ArrayList<>();
File fileAll = new File("/storage/emulated/0/Pictures/Camera2Demo/");
File[] files = fileAll.listFiles();
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (checkIsImageFile(file.getPath())) {
imagePathList.add(file.getPath());
}
}
得到所有的图片之后,将图片转换成 Base64
二进制流形式并添加到列表里
公开一个把文件转换成 Base64
的通用方法:
public static String encodeBase64File(String path) throws Exception {
byte[] videoBytes;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
@SuppressWarnings("resource")
FileInputStream fis = new FileInputStream(new File(path));
byte[] buf = new byte[1024];
int n;
while (-1 != (n = fis.read(buf)))
byteArrayOutputStream.write(buf, 0, n);
videoBytes = byteArrayOutputStream.toByteArray();
return Base64.encodeToString(videoBytes, Base64.NO_WRAP);
}
List<String> base64PhotoList = new ArrayList<>();
for (int i = 0; i < imagePathList.size(); i++) {
try {
// 将图片转换成 Base64
String base64PhotoFile = BitmapUtils.encodeBase64File(imagePathList.get(i));
// 将所有的 Base64 文件存到 List 里
base64PhotoList.add(base64PhotoFile);
} catch (Exception e) {
e.printStackTrace();
}
}
③ 显示图片
显示图片我们使用强大的 Glide
代替安卓默认的图片显示。
添加 Glide
库
implementation 'com.github.bumptech.glide:glide:4.4.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.4.0'
添加 RecyclerView
库
implementation 'com.android.support:recyclerview-v7:27.0.2'
单张显示:
Bitmap bitmap = BitmapFactory.decodeFile(imagePathList.get(i));
Glide.with(this).load(bitmap).into(图片布局);
显示所有图片:
创建 Adapter
,然后自定义一个 public
方法接收传来的列表数据。
private List<String> mList = new ArrayList<>();
public void setDataList(List<String> list) {
mList = list;
notifyDataSetChanged();
}
// 将列表数据传给 Adapter (在 Adapter 对应的 Activity 里执行)
mAdapter.setDataList(base64PhotoList);
在 onBindViewHolder
里面将图片依次显示出来
@Override
public void onBindViewHolder(MainViewHolder holder, int position) {
// Base64 转换成 Bitmap
Bitmap bitmap = BitmapUtils.convertToBitmap(mList.get(position));
Glide.with(mContext).load(bitmap).into(图片文件);
}
示例项目已上传至 GitHub
,如果对你有帮助请 Start
,谢谢!
关于 Camera2 最基本的用法就讲到这里。文章对你有帮助,给点个赞,关注我。谢谢!
网友评论