Android实现调用手机摄像头进行拍照并存储为文件

声明权限

首先应该在“AndroidManifest”文件中声明手机内存读写权限:

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

由于从Android 6.0开始,一些敏感权限需要在对应的Activity再次进行动态申请,因此,需要在我们编写的Activity里再次申请权限:

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
    
    
            ActivityCompat.requestPermissions(this, new String[]{
    
    Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
            Log.d("进入:", "requestPermissions");
        }
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
    
    
            ActivityCompat.requestPermissions(this, new String[]{
    
    Manifest.permission.READ_EXTERNAL_STORAGE}, 0);
            Log.d("进入:", "requestPermissions");
        }

拍照按钮触发事件`

1.拍照按钮的点击事件如下:

mBtnUpload.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                //点击事件:进行拍照
                Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                File photoFile=createImgFile();
                photoUri= Uri.fromFile(photoFile);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                startActivityForResult(intent,1);

            }
        });

2.上述“createImgFile()”函数的功能是自定义图片名,获取照片的file,具体代码如下:

/**
     * 自定义图片名,获取照片的file
     */
    private File createImgFile(){
    
    
        //确定文件名
        String fileName="img_"+new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date())+".jpg";
        File dir;
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
    
    
            dir=Environment.getExternalStorageDirectory();
        }else{
    
    
            dir=getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        }
        File tempFile=new File(dir,fileName);
        try{
    
    
            if(tempFile.exists()){
    
    
                tempFile.delete();
            }
            tempFile.createNewFile();
        }catch (IOException e){
    
    
            e.printStackTrace();
        }
        //获取文件路径
        photoPath = tempFile.getAbsolutePath();
        return tempFile;
    }

3.由于上述代码采用了“startActivityForResult()”方法,因此在拍照完成后会调用“onActivityResult()”函数。我们重写该函数(以实现照片存储、添加到相册中的功能):

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
    
        super.onActivityResult(requestCode, resultCode, data);
        if(resultCode==RESULT_OK){
    
    
            switch (requestCode){
    
    
                case 1:
                    setImageBitmap();
                    galleryAddPic();
                    break;
                case 2:
                    //data中自带有返回的uri
                    photoUri=data.getData();
                    //获取照片路径
                    String[] filePathColumn={
    
    MediaStore.Audio.Media.DATA};
                    Cursor cursor=getContentResolver().query(photoUri,filePathColumn,null,null,null);
                    cursor.moveToFirst();
                    photoPath=cursor.getString(cursor.getColumnIndex(filePathColumn[0]));
                    cursor.close();
                    //有了照片路径,之后就是压缩图片,和之前没有什么区别
                    setImageBitmap();
                    break;
            }
        }
    }

注:此处的“case 2”语句块用于从手机本地相册选取照片,由于代码类似,不再进行演示。
4.“setImageBitmap()”函数的功能是压缩我们刚刚拍到的图片,并将该图片展示在我们声明的“ImageView”控件中。具体代码如下:

/**
     * 压缩图片
     */
    private void setImageBitmap(){
    
    
        Log.d("Record", "进入压缩图片");
        //获取imageview的宽和高
        int targetWidth=photoImageView.getWidth();
        int targetHeight=photoImageView.getHeight();

        //根据图片路径,获取bitmap的宽和高
        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        BitmapFactory.decodeFile(photoPath,options);
        int photoWidth=options.outWidth;
        int photoHeight=options.outHeight;
        Log.d("Record", "获取长和高:"+ photoHeight + "Width:" + photoWidth);

        //获取缩放比例
        int inSampleSize=1;
        if(photoWidth>targetWidth||photoHeight>targetHeight){
    
    
            int widthRatio=Math.round((float)photoWidth/targetWidth);
            int heightRatio=Math.round((float)photoHeight/targetHeight);
            inSampleSize=Math.min(widthRatio,heightRatio);
            Log.d("Record", "进入缩放比例");
        }

        //使用现在的options获取Bitmap
        options.inSampleSize=inSampleSize;
        options.inJustDecodeBounds=false;
        Bitmap bitmap=BitmapFactory.decodeFile(photoPath,options);
        photoImageView.setImageBitmap(bitmap);
        //调用转换函数,将ImageView文件转换为String类型数据,以便传输到云端
        String bitmapToString = putImageToShare(getApplicationContext(), photoImageView);
        mTvChange.setText(bitmapToString);
        //调用上传函数,将String类型数据传送到服务器
        UploadImage(getApplicationContext(), bitmapToString);
        Log.d("Record", "ToString:" + bitmapToString);
        Log.d("Record", "获取Bitmap");
    }

其中的“putImageToShare()”、“UploadImage()”方法作用分别是图片转换成String类型的数据、将该数据上传至服务器。如果不需要实现照片上传至服务器的功能,可以删除这两行代码。如果需要实现上传功能,可以看这篇文章:
Android平台实现图片传输到服务器并在服务器文件夹中重现(客户端程序+服务器端程序)

5.“galleryAddPic()”函数的功能是将我们刚刚拍到的照片添加到手机相册中,具体代码如下:

//将图片添加进手机相册
    private void galleryAddPic(){
    
    
        Intent mediaScanIntent=new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        mediaScanIntent.setData(photoUri);
        this.sendBroadcast(mediaScanIntent);
    }

后记

记录一些编程过程中踩到的坑:
1.在Android 10中,读写手机内存权限还需要进行额外的操作:
在“AndroidManifest”文件中添加语句:

android:requestLegacyExternalStorage="true"

否则ImageView控件无法显示我们的图片。
2.在Android 10中,执行上述代码时,调用相机会闪退。解决方法如下:
在对应Activity中添加语句:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    
    
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy( builder.build() );
        }

参考文章:

https://blog.csdn.net/happy_fsyy/article/details/51986444
——————————————————————————
最后贴一下我的个人公众号:微信搜索“茶迁”或扫描下图。平时会更新一些编程相关的文章,欢迎大家关注~
茶迁

猜你喜欢

转载自blog.csdn.net/weixin_46269688/article/details/111307338