美文网首页
调用系统camera,返回缩略图or保存照片

调用系统camera,返回缩略图or保存照片

作者: ShanksWang | 来源:发表于2018-12-16 22:05 被阅读5次
  1. 声明需要相机支持
<manifest ... >
    <uses-feature android:name="android.hardware.camera"
                  android:required="true" />
    ...
</manifest>
  1. 拍照
// request code
static final int REQUEST_IMAGE_CAPTURE = 1;

private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // 确保有app响应这个拍照的请求
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // 调用相机,并等待结果
        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    }
}
  1. 简单方式取回拍照后的缩略图(thumbnail)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        Bundle extras = data.getExtras();
        Bitmap imageBitmap = (Bitmap) extras.get("data");
        mImageView.setImageBitmap(imageBitmap);
    }
}

注意:官方文档说,data参数获取到的数据,用于作为icon显示比较好。毕竟是缩略图嘛。

  1. 保存刚刚拍的照片呢
    申请权限先;
<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

用一个第三方库EasyPermission,去解决申请权限,参考官方文档或参考这里

1. 照片仅当前app可见

a. 通过使用getExternalFilesDir()获取到存储照片内部存储路径;举个例子有个app是takepic,它内部存储如下:Android/data/com.deao.takepic;文档中提到,Android4.4及其以后版本,访问内部存储不需要申请权限,反之,须声明。
b. 创建保存的图片文件名

// 后续,用于添加到相册,需要这个图片的绝对路径
String mCurrentPhotoPath;

private File createImageFile() throws IOException {
    // Create an image file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
    /*File storageDir = getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);

        if (!storageDir.exists()) {
            Log.d("TAG", "createImageFile: " + storageDir.mkdir());
        }*/
    // image 名称大概是:JPEG_20181216_200254_34**53.jpeg
    File image = File.createTempFile(
        imageFileName,  /* prefix */
        ".jpg",         /* suffix */
        storageDir      /* directory */
    );

    // Save a file: path for use with ACTION_VIEW intents
    mCurrentPhotoPath = image.getAbsolutePath();
    return image;
}

创建Intent并调用它如下:

static final int REQUEST_TAKE_PHOTO = 1;

private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    // Ensure that there's a camera activity to handle the intent
    if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
        // Create the File where the photo should go
        File photoFile = null;
        try {
            photoFile = createImageFile();
        } catch (IOException ex) {
            // Error occurred while creating the File
            ...
        }
        // Continue only if the File was successfully created
        if (photoFile != null) {
            // authorities="com.deao.takepic.fileprovider"
            Uri photoURI = FileProvider.getUriForFile(this,
                                                  "com.deao.takepic.fileprovider",
                                                  photoFile);
            // MUST be thrown FileUriExposedException
            // Uri photoURI = Uri.from(photo_file_path);
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
            startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
        }
    }
}

为适配7.0(API 24)或更高版本,通常要用FileProvider来处理路径了。如果还像之前那样传一个类似file://的URI,则会报FileUriExposedException。现在传的是content://的URL。

走,去AndroidManifest文件配置 FileProvider

<application>
   ...
   <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.deao.takepic.fileprovider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"></meta-data>
    </provider>
    ...
</application>

然后,到res/xml/file_paths查看下我们的文件路径配置;

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-files-path name="my_images" path="Android/data/com.deao.takepic/files/Pictures" />
    <external-path name="my_images" path="Pictures" />
</paths>

解释:类似于对FileProvider的声明,以上声明了两个路径的请求内容的URI(request content URI)。<external-files-path name="my_images" path="Android/data/com.deao.takepic/files/Pictures" />,声明图片保存到takepic app的私人文件夹内,其他应用都不能访问;<external-path name="my_images" path="Pictures" />,声明到图片保存到外置存储器的Pictures目录下,对设备上所有app可见,当然,添加到相册也是可以的。

更多细节参考这里FileProvider#SpecifyFiles
下面再onActivityResult回调中等待结果。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
        Bundle extras = data.getExtras();
        Bitmap imageBitmap = (Bitmap) extras.get("data");
        mImageView.setImageBitmap(imageBitmap);
    }
    // galleryAddPic();
}

2. 照片所有app可见

...

添加到相册(Gallery)

// mCurrentPhotoPath = ""
private void galleryAddPic() {
    Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
    File f = new File(mCurrentPhotoPath);
    Uri contentUri = Uri.fromFile(f);
    mediaScanIntent.setData(contentUri);
    this.sendBroadcast(mediaScanIntent);
}

注意事项:如果相片是存储该app到getExternalFileDir()目录下的,media scanner是无法访问的,也就无法添加到相册;其他app也无法访问。

参考:
Camera | takephotos
FileProvider#SpecifyFiles

相关文章

网友评论

      本文标题:调用系统camera,返回缩略图or保存照片

      本文链接:https://www.haomeiwen.com/subject/lloxkqtx.html