文章目录
一、调用摄像头
新建项目 CameraAlbumTest
项目
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
// 用于发起相机
<Button
android:id="@+id/takePhotoBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Take Photo"
android:textAllCaps="false"/>
// 显示拍摄的照片
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
private File outputImage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button takePhoto = findViewById(R.id.takePhotoBtn);
picture = findViewById(R.id.imageView);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 创建 File 对象,用于存储拍照的图片,命名为 output_image.jpg
// 并将图片存放在手机 SD 卡应用关联缓存目录下。
// 应用关联缓存目录就是指 SD 卡中专门用于存放当前应用缓存数据的位置,
// 调用 getExternalCacheDir() 方法可以得到这个目录, 具体的路径为 /sdcard/Android/data/<package name>/cache
// 为什么要使用应用关联目录来存放图片呢?
/**
* 因为从Android 6.0系统开始,读写SD卡被列为了危险权限,
* 如果将图片存放在SD卡的任何其他目录,都要进行运行时权限处理才行,而使用应用关联目录则可以跳过这一步。
* 另外,从Android 10.0系统开始,公有的SD卡目录已经不再允许被应用程序直接访问了,而是要使用作用域存储才行。
*/
outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (Exception e) {
e.printStackTrace();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 系统版本高于 7.0
/**
* 调用 FileProvider.getUriForFile() 方法将 File 对象转化为封装过的 Uri 对象
* 之所以要进行这样一层转换,是因为从 Android 7.0系统开始,
* 直接使用本地真实路径的 Uri 被认为是不安全的,会抛出一个 FileUriExposedException 异常。
* 而 FileProvider 则是一种特殊的 ContentProvider,它使用了和 ContentProvider 类似的机制来对数据进行保护,
* 可以选择性地将封装过的 Uri 共享给外部,从而提高了应用的安全性
*
* param Context
* param 任意唯一的字符串
* param File 对象
*/
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraalbumtest.fileprovider", outputImage);
} else {
// 系统版本低于 7.0, 就调用 Uri.fromFile() 将 File 对象转化为封装过的 Uri 对象
imageUri = Uri.fromFile(outputImage);
}
// 启动相机程序,隐式跳转
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
// 这里指定图片的输出地址,这里填入刚刚得到的Uri对象
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
// 启动相机,拍下的照片将会输出到 output_image.jpg 中
startActivityForResult(intent, TAKE_PHOTO);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO:
// 判断是否拍照成功
if (resultCode == RESULT_OK) {
try {
// 将拍摄照片显示出来
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(rotateIfRequired(bitmap));
} catch (Exception e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
/**
* 需要注意的是,调用照相机程序去拍照有可能会在一些手机上发生照片旋转的情况。
* 这是因为这些手机认为打开摄像头进行拍摄时手机就应该是横屏的,因此回到竖屏的情况下就会发生90度的旋转。
* 为此,这里我们又加上了判断图片方向的代码,如果发现图片需要进行旋转,那么就先将图片旋转相应的角度,然后再显示到界面上。
* @param bitmap
* @return
*/
private Bitmap rotateIfRequired(Bitmap bitmap) {