Android 四大组件之 Activity_ 获取拍照结果(startActivityForResult &onActivityResult)

通过startActivityForResult 调用相机拍照,  并由onActivityResult回调返回拍照的结果

目录

1. 获取缩略图

2.保存完整尺寸的照片

(1) 读写目录的权限

(2) 创建图片文件(文件三要素: 名称、格式、所在路径)

(3) 使用FileProvider 产生Uri

(4) 调用startActivityForResult, 并将Uri提供给Camera 存储图片(由MediaStore.EXTRA_OUTPUT 携带给Camera)

(5) 查看存储图片的路径

(6) 注意事项


1. 获取缩略图

    private void dispatchTakePictureIntent() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //resolveActivity 返回可处理 Intent 的第一个 Activity 组件
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
        }
    }

Intent 的action为: MediaStore.ACTION_IMAGE_CAPTURE

则返回的结果在intent 对象的Bundle 对象中, 再通过Bundle 对象获取 数据data位图

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

2.保存完整尺寸的照片

需要保存在 设备的公共外部存储设备,以供所有应用访问。

合适的共享照片目录由具有 DIRECTORY_PICTURES 参数的 getExternalStoragePublicDirectory() 提供。

(1) 读写目录的权限

需要对目录有读写权限 :对该目录执行读写操作  READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 权限。(写权限默认包含了读的权限)

    <manifest ...>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        ...
    </manifest>

并且也要给用户存储的权限,否则程序会崩溃。(参考上一篇的权限验证:https://blog.csdn.net/whjk20/article/details/113746500)

(2) 创建图片文件(文件三要素: 名称、格式、所在路径)

根据日期-时间戳的新照片返回一个独一无二文件名

    String currentPhotoPath;
    private File createImageFile() throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName, /* prefix */
                ".jpg", /* suffix */
                storageDir /* directory */
        );
        //Save a file: path for use with ACTION_VIEW intents
        currentPhotoPath = image.getAbsolutePath();
        return image;
    }
currentPhotoPath 为图片保存的路径,当成功返回结果时,就可以取出图片(后续)

 存储文件路径  File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);

这个对应表示存储在当前APP的路径下: /storage/emulated/0/Android/data/com.example.activitytest/files/Pictures/

(3) 使用FileProvider 产生Uri (进程间传递数据)

photoFile = createImageFile();
Uri photoURI = FileProvider.getUriForFile(this, "com.example.activitytest.fileprovider", photoFile);

其中"com.example.activitytest.fileprovider" 为使用到的 FileProvider 的标识

需要在AndroidManifest 中声明FileProvider

    <application/>

        <provider
            android:authorities="com.example.activitytest.fileprovider"
            android:name="androidx.core.content.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 

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

(4) 调用startActivityForResult, 并将Uri提供给Camera 存储图片(由MediaStore.EXTRA_OUTPUT 携带给Camera)

完整调用代码:

    private void dispatchTakePictureIntent2() {
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        //resolveActivity 返回可处理 Intent 的第一个 Activity 组件
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            // Create the File where the photo should go
            File photoFile = null;
            try {
                photoFile = createImageFile();
            } catch (IOException e) {
                // Error occurred while creating the File
                e.printStackTrace();
            }
            // Continue only if the File was successfully created
            if (photoFile != null) {
                Uri photoURI = FileProvider.getUriForFile(this,
                        "com.example.activitytest.fileprovider",
                        photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
            }
        }
    }

(5) 查看存储图片的路径

可以通过Android studio 的Device File Explorer 查看

/storage/emulated/0/Android/data/com.example.activitytest/files/Pictures/JPEG_20210209_113934_1896150229632986072.jpg

(6) 注意事项

参考官网例子,FileProvider 的元数据配置 external-files-path 为如下,

<external-files-path name="my_images" path="Android/data/com.example.package.name/files/Pictures" />

实际上会发生FC,例如报错误:

FATAL EXCEPTION: main
Process: com.example.marek.myapplication, PID: 6747
java.lang.IllegalArgumentException: Failed to find configured root that contains /storage/emulated/0/Android/data/com.example.marek.myapplication/files/Pictures/JPEG_20170228_175633_470124220.jpg
 

解决方法为: path="."

参考:https://stackoverflow.com/questions/42516126/fileprovider-illegalargumentexception-failed-to-find-configured-root    

<?xml version="1.0" encoding="utf-8"?>
<paths>
  <external-path
    name="external"
    path="." />
  <external-files-path
    name="external_files"
    path="." />
  <cache-path
    name="cache"
    path="." />
  <external-cache-path
    name="external_cache"
    path="." />
<files-path
    name="files"
    path="." />
</paths>

参考官网: https://developer.android.com/training/camera/photobasics

3. 添加图片到相册中(未成功,待续)

尝试发广播 (ACTION_MEDIA_SCANNER_SCAN_FILE) 和  MediaScannerConnection 主动发送都不行

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

    private MediaScannerConnectionClient mediaScannerConnectionClient =
            new MediaScannerConnectionClient() {

                @Override
                public void onMediaScannerConnected() {
                    //Toast.makeText(mContext, "onMediaScannerConnected", Toast.LENGTH_LONG).show();
                    log.info("onMediaScannerConnected");
                    mediaScannerConnection.scanFile(currentPhotoPath, null);
                }

                @Override
                public void onScanCompleted(String path, Uri uri) {
                    //Toast.makeText(mContext, "onScanCompleted path="+path + ", uri="+path, Toast.LENGTH_LONG).show();
                    log.info("onScanCompleted path="+path + ", uri="+path);
                    if (path.equals(currentPhotoPath))
                        mediaScannerConnection.disconnect();
                }
            };

    MediaScannerConnection mediaScannerConnection = new MediaScannerConnection(this, mediaScannerConnectionClient);

    private void galleryAddPic() {
        log.info("galleryAddPic currentPhotoPath=" + currentPhotoPath);
//        Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
//        File file = new File(currentPhotoPath);
//        //Uri contentUri = Uri.fromFile(file);
//        Uri contentUri = FileProvider.getUriForFile(this, "com.example.activitytest.fileprovider", file);
//        mediaScanIntent.setData(contentUri);
//        this.sendBroadcast(mediaScanIntent);

        mediaScannerConnection.connect();
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值