Android 调用相机以及从相册中选择图片

文章目录

  • 调用相机拍照并显示
  • 选取相册照片显示


调用相机拍照并显示

MainActivity.java:

public class MainActivity extends AppCompatActivity {

    public static final int TAKE_PHOTO = 1;
    public static final int CHOOSE_PHOT0 = 2;
    private Uri imageUri;
    private ImageView picture;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button takePhoto = findViewById(R.id.take_photo);
        picture = findViewById(R.id.picture);
        takePhoto.setOnClickListener(view -> {
            File outputFile = new File(getExternalCacheDir(),"output_image.jpg");
            //getExternalCacheDir()方法得到当前应用缓存数据位置
            try {
                if (outputFile.exists()) {
                    outputFile.delete();
                }
                outputFile.createNewFile();
                imageUri = FileProvider.getUriForFile(this,
                        "com.example.cameraalbumtest.fileprovider",outputFile);
                //启动相机程序
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                if (intent.resolveActivity(getPackageManager()) != null){
                    startActivityForResult(intent, TAKE_PHOTO);//第二个参数是请求码
                }
                } catch (IOException e) {
                    e.printStackTrace();
            }
        });        
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == TAKE_PHOTO && resultCode == RESULT_OK) {
            try {
                Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver()
                        .openInputStream(imageUri));
                picture.setImageBitmap(BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri)));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

Android 7.0及以上要求我们用fileprovider,禁止应用将 file:// 开头的Uri共享给其他的应用读写文件,否则会收到FileUriExposedException的异常。FileProvider生成的Uri会使用我们自己配置的的name属性替换真实的文件路径。
在AndroidManifest.xml中添加provider标签:

<application>
	...
	<provider
		android:authorities="com.example.cameraalbumtest.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"/>
	provider>
	...
application>

之后在 res/xml 文件夹下创建文件 file_paths.xml:


<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-cache-path name="my_images" path="." />
paths>

其中 external-cache-path标签对应getExternalCacheDirs()
name就是我们想要替换上去的名称,这样外部应用即使拿到Uri也无法知到具体的存储位置。

说明:
if (intent.resolveActivity(getPackageManager()) != null) 用来判断是否有对应的action来相应这个intent,如果有再startActivity。


选取相册照片显示

public class MainActivity extends AppCompatActivity {

    public static final int CHOOSE_PHOT0 = 2;
    private Uri imageUri;
    private ImageView picture;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        picture = findViewById(R.id.picture);
        Button chooseFromAlbum = findViewById(R.id.choose_from_album);
        chooseFromAlbum.setOnClickListener(view -> {
            //动态申请权限
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.
                            PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            } else {
                openAlbum();
            }
        });
    }

    private void openAlbum() {
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent, CHOOSE_PHOT0);//打开相册
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        if(requestCode == 1) {
            if (grantResults.length > 0 && grantResults[0]==PackageManager.
                    PERMISSION_GRANTED) {

//                openAlbum();
            } else {
                Log.d("tag",String.valueOf(grantResults[0]));
                Toast.makeText(this,"You denied the permission",
                        Toast.LENGTH_SHORT).show();
            }
        }
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == CHOOSE_PHOT0 && resultCode == RESULT_OK) {
            if (Build.VERSION.SDK_INT >= 19) {
                //4.4及以上系统选取相册中的图片不再返回图片的真实Uri了,而是
                //一个封装过的Uri,需要对这个Uri进行解析。
                handleImageOnKitKat(data);
            } else {
                handleImageBeforeKitKat(data);
            }
        }
    }

    @TargetApi(19)
    private void handleImageOnKitKat(Intent data) {
        //解析封装过的Uri
        String imagePath = null;
        Uri uri = data.getData();
        if (DocumentsContract.isDocumentUri(this ,uri)) {
            //如果是document类型的Uri,则通过document id处理
            String docId = DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())) {
                String id = docId.split(":")[1];//解析出数字格式的id
                String selection = MediaStore.Images.Media._ID + "=" +id;
                imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                        selection);
            } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) {
                Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"),
                        Long.valueOf(docId));
                imagePath = getImagePath(contentUri, null);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            //如果是content类型的Uri,则使用普遍方式处理
            imagePath = getImagePath(uri, null);
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            //如果是file类型的Uri,直接获取图片路径即可
            imagePath = uri.getPath();
        }
        displayImage(imagePath);
    }

    private void handleImageBeforeKitKat(Intent data) {
        Uri uri = data.getData();
        String imagePath = getImagePath(uri,null);
        displayImage(imagePath);
    }

    private String getImagePath(Uri uri, String selection) {
        String path=null;
        //通过Uri和selection类获取真实的图片路径
        Cursor cursor = getContentResolver().query(uri,null,selection, null ,null);
        if (cursor != null) {
            if(cursor.moveToFirst()) {
                int index = cursor.getColumnIndex(MediaStore.
                        Images.Media.DATA);
                path = cursor.getString(index);
            }
            cursor.close();
        }
        return path;
    }

    private void displayImage(String imagePath) {
        if (imagePath != null) {
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
            picture.setImageBitmap(bitmap);
        } else {
            Toast.makeText(this,"failed to get image", Toast.LENGTH_SHORT).show();
        }
    }
}

在 AndroidManifest.xml 中需要加入权限:

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

在 Android Q 以后采用隔离存储,WRITE_EXTERNAL_STORAGE 只有了对媒体内容进行读写的权限。在本应用的存储沙盒之中读写不需要权限。

你可能感兴趣的:(Android,学习,android)