【安卓】调用摄像头和相册
文章目录
- 调用摄像头拍照
- 从相册中选择照片
调用摄像头拍照
新建一个CameraAlbumTest项目,然后修改activity_main.xml中的代码。在布局文件中添加两个控件:一个Button和一个ImageView。Button是用于打开摄像头进行拍照的,而ImageView则是用于将拍到的图片显示出来。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent" ><Buttonandroid:id="@+id/takePhotoBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Take Photo" /><ImageViewandroid:id="@+id/imageView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal" />
</LinearLayout>
编写调用摄像头的具体逻辑,修改MainActivity中的代码。给Button注册点击事件,然后在点击事件里开始处理调用摄像头的逻辑。
public class MainActivity extends AppCompatActivity {public static final int TAKE_PHOTO = 1;private ImageView picture;private Uri imageUri;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button takePhoto = (Button) findViewById(R.id.takePhotoBtn);picture = (ImageView) findViewById(R.id.imageView);takePhoto.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v) {// 创建File对象,用于存储拍照后的图片File outputImage = new File(getExternalCacheDir(), "output_image.jpg");try {if(outputImage.exists()){outputImage.delete();}outputImage.createNewFile();} catch (IOException e){e.printStackTrace();}if (Build.VERSION.SDK_INT >= 24) {imageUri = FileProvider.getUriForFile(MainActivity.this,"com.example.cameraalbumtest.fileprovider", outputImage);} else {imageUri = Uri.fromFile(outputImage);}// 启动相机程序Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);startActivityForResult(intent, TAKE_PHOTO);}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, 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(bitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}break;default:break;}}
}
getUriForFile()方法接收3个参数:第一个参数要求传入Context对象,第二个参数可以是任意唯一的字符串,第三个参数则是File对象。
修改AndroidManifest.xml文件。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.CameraAlbumTest"tools:targetApi="31"><providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.example.cameraalbumtest.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/file_paths" /></provider><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>
添加资源文件file_paths.xml。在res文件下找到xml目录(如果没有在res目录下新建目录)新建file,取名file_paths.xml。然后修改file_paths.xml文件中的内容。
<?xml version="1.0" encoding="UTF-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"><external-path name="my_images" path="/" />
</paths>
external-path就是用来指定Uri共享路径的,name属性的值可以随便填,path属性的值表示共享的具体路径。
从相册中选择照片
修改activity_main.xml文件,在布局中加入一个新按钮。
<Buttonandroid:id="@+id/fromAlbumBtn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="From Album" />
然后修改MainActivity中的代码,加入从相册选择图片的逻辑。
public class MainActivity extends AppCompatActivity {public static final int TAKE_PHOTO = 1;private ImageView picture;private Uri imageUri;public static final int CHOOSE_PHOTO = 2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button takePhoto = (Button) findViewById(R.id.takePhotoBtn);Button chooseFromAlbum = (Button) findViewById(R.id.fromAlbumBtn);picture = (ImageView) findViewById(R.id.imageView);takePhoto.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v) {// 创建File对象,用于存储拍照后的图片File outputImage = new File(getExternalCacheDir(), "output_image.jpg");try {if(outputImage.exists()){outputImage.delete();}outputImage.createNewFile();} catch (IOException e){e.printStackTrace();}if (Build.VERSION.SDK_INT >= 24) {imageUri = FileProvider.getUriForFile(MainActivity.this,"com.example.cameraalbumtest.fileprovider", outputImage);} else {imageUri = Uri.fromFile(outputImage);}// 启动相机程序Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);startActivityForResult(intent, TAKE_PHOTO);}});chooseFromAlbum.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v) {if (ContextCompat.checkSelfPermission(MainActivity.this,android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ActivityCompat.requestPermissions(MainActivity.this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);} else {openAlbum();}}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, 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(bitmap);} catch (FileNotFoundException e) {e.printStackTrace();}}break;case CHOOSE_PHOTO:if (resultCode == RESULT_OK) {// 判断手机系统版本号if (Build.VERSION.SDK_INT >= 19){// 4.4及以上系统使用这个方法处理图片handleImageOnKitKat(data);} else {// 4.4以下系统使用这个方法处理图片handleImageBeforeKitKat(data);}}break;default:break;}}// 打开相册private void openAlbum() {Intent intent = new Intent("android.intent.action.GET_CONTENT");intent.setType("image/*");startActivityForResult(intent, CHOOSE_PHOTO); // 打开相册}public void onRequestPermissionResult(int requestCode, String[] permissions,int[] grantREsults){switch (requestCode) {case 1:if (grantREsults.length > 0 && grantREsults[0] == PackageManager.PERMISSION_GRANTED){openAlbum();} else {Toast.makeText(this, "You denied the permission",Toast.LENGTH_SHORT).show();}break;default:break;}}@TargetApi(19)private void handleImageOnKitKat(Intent data) {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]; // 解析出数字格式的idString 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()) {path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));}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 iamge", Toast.LENGTH_SHORT).show();}}
}
在AndroidManifest.xml中进行授权
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
此时运行程序会报一个错:Unable to decode stream: java.io.FileNotFoundException,没查到错是什么原因导致的,但是有解决方法。在application中加一句:
android:requestLegacyExternalStorage=“true”