今天寫的博客是關(guān)于Android調(diào)用手機(jī)相機(jī)拍照并顯示圖片咖祭。這是一個(gè)很常用的功能掩宜,并且這個(gè)功能在Android6.0、7.0么翰、10.0等版本上實(shí)現(xiàn)都有所不同牺汤,需要對(duì)Android各個(gè)版本進(jìn)行兼容適配,目前最新的Android版本是Android 10浩嫌,所以這篇博客適配到Android 10檐迟。我自己也寫了個(gè)demo,方便以后要使用的時(shí)候直接拿來码耐。
調(diào)用相機(jī)追迟,首先需要申請(qǐng)相機(jī)權(quán)限。
<uses-permission android:name="android.permission.CAMERA" />
android 6.0以后骚腥,相機(jī)權(quán)限需要?jiǎng)討B(tài)申請(qǐng)敦间。
// 申請(qǐng)相機(jī)權(quán)限的requestCode
private static final int PERMISSION_CAMERA_REQUEST_CODE = 0x00000012;
/**
* 檢查權(quán)限并拍照。
* 調(diào)用相機(jī)前先檢查權(quán)限束铭。
*/
private void checkPermissionAndCamera() {
int hasCameraPermission = ContextCompat.checkSelfPermission(getApplication(),
Manifest.permission.CAMERA);
if (hasCameraPermission == PackageManager.PERMISSION_GRANTED) {
//有調(diào)起相機(jī)拍照廓块。
openCamera();
} else {
//沒有權(quán)限,申請(qǐng)權(quán)限纯露。
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},
PERMISSION_CAMERA_REQUEST_CODE);
}
}
/**
* 處理權(quán)限申請(qǐng)的回調(diào)剿骨。
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == PERMISSION_CAMERA_REQUEST_CODE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//允許權(quán)限,有調(diào)起相機(jī)拍照埠褪。
openCamera();
} else {
//拒絕權(quán)限,彈出提示框挤庇。
Toast.makeText(this,"拍照權(quán)限被拒絕",Toast.LENGTH_LONG).show();
}
}
}
申請(qǐng)權(quán)限后钞速,就可以調(diào)起相機(jī)拍照了。調(diào)用相機(jī)只需要調(diào)用startActivityForResult傳一個(gè)Intent就可以了嫡秕,但是這個(gè)Intent需要傳遞一個(gè)uri渴语,用于保存拍出來的圖片,創(chuàng)建這個(gè)uri時(shí)昆咽,各個(gè)Android版本有所不同驾凶,需要進(jìn)行版本兼容牙甫。
//用于保存拍照?qǐng)D片的uri
private Uri mCameraUri;
// 用于保存圖片的文件路徑,Android 10以下使用圖片路徑訪問圖片
private String mCameraImagePath;
// 是否是Android 10以上手機(jī)
private boolean isAndroidQ = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;
/**
* 調(diào)起相機(jī)拍照
*/
private void openCamera() {
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 判斷是否有相機(jī)
if (captureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
Uri photoUri = null;
if (isAndroidQ) {
// 適配android 10
photoUri = createImageUri();
} else {
try {
photoFile = createImageFile();
} catch (IOException e) {
e.printStackTrace();
}
if (photoFile != null) {
mCameraImagePath = photoFile.getAbsolutePath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//適配Android 7.0文件權(quán)限调违,通過FileProvider創(chuàng)建一個(gè)content類型的Uri
photoUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", photoFile);
} else {
photoUri = Uri.fromFile(photoFile);
}
}
}
mCameraUri = photoUri;
if (photoUri != null) {
captureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
captureIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivityForResult(captureIntent, CAMERA_REQUEST_CODE);
}
}
}
/**
* 創(chuàng)建圖片地址uri,用于保存拍照后的照片 Android 10以后使用這種方法
*/
private Uri createImageUri() {
String status = Environment.getExternalStorageState();
// 判斷是否有SD卡,優(yōu)先使用SD卡存儲(chǔ),當(dāng)沒有SD卡時(shí)使用手機(jī)存儲(chǔ)
if (status.equals(Environment.MEDIA_MOUNTED)) {
return getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
} else {
return getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues());
}
}
/**
* 創(chuàng)建保存圖片的文件
*/
private File createImageFile() throws IOException {
String imageName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
if (!storageDir.exists()) {
storageDir.mkdir();
}
File tempFile = new File(storageDir, imageName);
if (!Environment.MEDIA_MOUNTED.equals(EnvironmentCompat.getStorageState(tempFile))) {
return null;
}
return tempFile;
}
接收拍照結(jié)果和顯示圖片
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CAMERA_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
if (isAndroidQ) {
// Android 10 使用圖片uri加載
ivPhoto.setImageURI(mCameraUri);
} else {
// 使用圖片路徑加載
ivPhoto.setImageBitmap(BitmapFactory.decodeFile(mCameraImagePath));
}
} else {
Toast.makeText(this,"取消",Toast.LENGTH_LONG).show();
}
}
}
這兩需要說明一下窟哺,Android 10由于文件權(quán)限的關(guān)系,顯示手機(jī)儲(chǔ)存卡里的圖片不能直接使用圖片路徑技肩,需要使用圖片uri加載且轨。關(guān)于在Android 10顯示手機(jī)圖片的適配可以看我的另外一篇博客:Android 10加載手機(jī)本地圖片
另外雖然我在這篇博客里對(duì)Android 10和10以下的手機(jī)使用了不同的方式創(chuàng)建uri 和加載圖片,但其實(shí)Android 10創(chuàng)建uri的方式和使用uri加載圖片的方式在10以下的手機(jī)是同樣適用的虚婿。
android 7.0需要配置文件共享旋奢。
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
在res目錄下創(chuàng)建文件夾xml ,放置一個(gè)文件file_paths.xml(文件名可以隨便取)然痊,配置需要共享的文件目錄至朗,也就是拍照?qǐng)D片保存的目錄。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<!-- 這個(gè)是保存拍照?qǐng)D片的路徑,必須配置剧浸。 -->
<external-files-path
name="images"
path="Pictures" />
</paths>
</resources>
如果想把圖片放在手機(jī)的共享儲(chǔ)存區(qū)锹引,比如Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)文件夾下,還需要申請(qǐng)文件讀寫權(quán)限辛蚊。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
文件讀寫權(quán)限同樣需要?jiǎng)討B(tài)申請(qǐng)粤蝎,申請(qǐng)權(quán)限的方式跟上面申請(qǐng)相機(jī)權(quán)限一樣,這里就不再重復(fù)了袋马。
完整的demo請(qǐng)看我的Github初澎。