本篇在android手機(jī)上調(diào)用攝像頭拍照。
新建項(xiàng)目MyCameraAlbum,然后修改activity_main.xml中的代碼。
<?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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cofox.mycameraalbum.MainActivity">
<Button
android:id="@+id/button_take_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="Tack Photo"/>
<ImageView
android:id="@+id/photo_pictrue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
布局中只有兩個(gè)控件,一個(gè)Button,一個(gè)ImageView。Button是打開攝像頭的按鈕,ImageView則是用來(lái)顯示拍到的圖片。
調(diào)用攝像頭的具體邏輯,修改MainActivity中的代碼:
public class MainActivity extends AppCompatActivity {
public static final int TAKE_PHOTO = 1;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnTakePhoto = (Button) findViewById(R.id.button_take_photo); //按鈕
picture = (ImageView) findViewById(R.id.photo_pictrue); //圖片控件,用來(lái)顯示照片的。
btnTakePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//創(chuàng)建File對(duì)象,用于存儲(chǔ)拍照后的圖片
File outputImage = new File(getExternalCacheDir(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
//android 7.0版本以下的系統(tǒng),直接Uri.fromFile取得真實(shí)文件路徑;7.0及以上版本的系統(tǒng),使用fileprovider封裝過(guò)的Uri再提供出去。
if (Build.VERSION.SDK_INT >= 24) {
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.cofox.mycameraalbum.fileprovider", outputImage);
} else {
imageUri = Uri.fromFile(outputImage);
}
//啟動(dòng)相機(jī)程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO); //啟動(dòng)Intent活動(dòng),拍完照會(huì)有結(jié)果返回到onActivityResult()方法中。
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PHOTO:
if(resultCode == RESULT_OK){
try {
//將拍攝的照片顯示出來(lái)
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
}
這段代碼,首先分別獲取到Button和ImageView的實(shí)例,并給Button注冊(cè)點(diǎn)擊事件。在點(diǎn)擊事件里開始處理調(diào)用攝像頭的邏輯。
首先創(chuàng)建一個(gè)File對(duì)象,用戶存儲(chǔ)攝像頭拍下的圖片。這里命名圖片名稱為outout_image.jpg,并將它存放在手機(jī)應(yīng)用關(guān)聯(lián)緩存目錄下。
應(yīng)用關(guān)聯(lián)緩存目錄是指專門用于存放當(dāng)前應(yīng)用緩存數(shù)據(jù)的位置,調(diào)用getExternalCacheDir()方法可以得到這個(gè)目錄。具體路徑是/sdcard/Android/data/<package name>/cache。
之所以使用應(yīng)用緩存來(lái)存放圖片,是因?yàn)閺腶ndroid 6.0系統(tǒng)開始,讀寫SD卡被列為了危險(xiǎn)權(quán)限,圖片要存放在SD卡的任何其他目錄,都要進(jìn)行運(yùn)行時(shí)權(quán)限處理,而使用應(yīng)用關(guān)聯(lián)目錄則可以跳過(guò)這一步。
if (Build.VERSION.SDK_INT >= 24) {
imageUri = FileProvider.getUriForFile(MainActivity.this, "com.cofox.mycameraalbum.fileprovider", outputImage);
} else {
imageUri = Uri.fromFile(outputImage);
}
這段代碼,是根據(jù)當(dāng)前android系統(tǒng)的版本,提供不同的Uri。
android 7.0一下版本,使用真實(shí)文件路徑。
Uri.fromFile(outputImage)
7.0及以上版本的系統(tǒng),使用fileprovider封裝過(guò)的Uri再提供出去。
FileProvider.getUriForFile(MainActivity.this, "com.cofox.mycameraalbum.fileprovider", outputImage)
FileProvider是一種特殊的內(nèi)容提供器,使用了內(nèi)容提供器類似的機(jī)制來(lái)對(duì)數(shù)據(jù)進(jìn)行保護(hù),可以選擇性地將封裝過(guò)的Uri共享給外部,從而提高了安全性。
之后構(gòu)建一個(gè)Intent對(duì)象,并將這個(gè)Intent的action指定為android.media.action.IMAGE_CAPTURE,再調(diào)用Intent的putExtra()指定圖片的輸出地址,這里填入剛剛得到的Uri對(duì)象。最后startActivityForResult()來(lái)啟動(dòng)活動(dòng)。
startActivityForResult(intent, TAKE_PHOTO);
使用startActivityForResult()來(lái)啟動(dòng)活動(dòng)的,拍照結(jié)束會(huì)有結(jié)果返回onActivityResult()。
如果拍照成功
resultCode == RESULT_OK
調(diào)用BitmapFactory的decodeStream()方法將output_image.jpg解析成Bitmap對(duì)象,然后設(shè)置到ImageView中顯示出來(lái)。
代碼中使用的內(nèi)容提供器,必須在AndroidManifest.xml中對(duì)內(nèi)容提供器進(jìn)行注冊(cè)。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cofox.mycameraalbum">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:authorities="com.cofox.mycameraalbum.fileprovider"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
在android:authorities屬性的值必須和剛才FileProvider.getUrlFile()方法中的第二個(gè)參數(shù)一致。
<provider>標(biāo)簽的內(nèi)部使用<meta-date>來(lái)指定Url的共享路徑,并引用了一個(gè)@xml/file_paths資源。這個(gè)資源現(xiàn)在還不存在,馬上創(chuàng)建。
右擊res目錄->New->Directory,創(chuàng)建一個(gè)xml目錄;右擊這個(gè)xml目錄->New->File,創(chuàng)建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>
這里的extenal-path是用來(lái)指定Uri共享的。path屬性的值就是表示共享的具體路徑。當(dāng)前為空的設(shè)置,表示將整個(gè)SD卡進(jìn)行共享。
最后一點(diǎn)要注意的,如果是古老的android 4.4之前的系統(tǒng),訪問SD卡的應(yīng)用關(guān)聯(lián)目錄要聲明權(quán)限。android 4.4不需要聲明。為了兼容那些老版本的系統(tǒng),在AndroidManifest.xml中聲明SD的訪問權(quán)限。
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

