Android 进阶之路Android开发程序员

【 Android 】Camera2 初探

2017-12-23  本文已影响57人  Tyhoo_Wu

调用手机摄像头,在当今的众多 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 上显示照片(显示最后一张,显示所有拍照的图片)

重点:
① 调用系统相机
startActivityForResultonActivityResult 的使用
③ 显示所有的图片,我们这里使用 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 最基本的用法就讲到这里。文章对你有帮助,给点个赞,关注我。谢谢!

上一篇 下一篇

猜你喜欢

热点阅读