注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術(shù)一般,由于喜愛安卓而產(chǎn)生了翻譯的念頭,純屬個(gè)人興趣愛好。
原文鏈接: http://developer.android.com/training/camera/photobasics.html
這節(jié)課將展示如何使用已經(jīng)存在的相機(jī)應(yīng)用拍攝相機(jī)。
假設(shè)你現(xiàn)在在實(shí)現(xiàn)一個(gè)基于人群的氣象服務(wù),它構(gòu)建一個(gè)全球的氣象地圖,通過將運(yùn)行了你的應(yīng)用色設(shè)備所拍攝的天空照片拼接起來來實(shí)現(xiàn)這個(gè)氣象地圖。整合照片只是你的應(yīng)用的一小部分。你希望通過最簡單地方式拍攝照片,而不是需要重新構(gòu)造一個(gè)相機(jī)。大多數(shù)Android設(shè)備其實(shí)已經(jīng)至少有了一個(gè)相機(jī)應(yīng)用。在這節(jié)課中,你將學(xué)習(xí)如何利用它來為您拍攝一個(gè)照片。
一). 請求相機(jī)權(quán)限
如果你的應(yīng)用中一個(gè)重要的函數(shù)會(huì)拍攝照片,同時(shí)限制只有那些擁有相機(jī)的設(shè)備可以在Google Play上下載。為了聲明你的應(yīng)用依賴于一個(gè)相機(jī),在你的清單文件中放置一個(gè)
<uses-feature>
標(biāo)簽:
<
manifest
...
>
<
uses-feature
android:name
="android.hardware.camera"
android:required
="true"
/>
...
</
manifest
>
如果你的應(yīng)用使用,但并不依賴一個(gè)相機(jī)來執(zhí)行功能,那么將“ android:required ”設(shè)置為“ false ”。這樣的話,那么Google Play將會(huì)允許沒有相機(jī)的設(shè)備下載你的應(yīng)用。那么接下來就是你的責(zé)任在運(yùn)行時(shí)如果調(diào)用了需要用相機(jī)的函數(shù)時(shí), 通過調(diào)用 hasSystemFeature(PackageManager.FEATURE_CAMERA) 檢查是否可以獲取相機(jī)。如果相機(jī)無法獲取,那么你就應(yīng)該禁止你的相關(guān)功能特性。
二). 使用相機(jī)應(yīng)用拍攝照片
在Android中向其它應(yīng)用分發(fā)意圖是通過激活一個(gè)描述你的意圖的
Intent
。這一過程分為三步:
Intent
自身,調(diào)用外部
Activity
,當(dāng)焦點(diǎn)回到你的activity中處理圖像數(shù)據(jù)的一些代碼。
下面的代碼是構(gòu)造一個(gè)intent來獲取一張照片。
static
final
int
REQUEST_IMAGE_CAPTURE = 1
;
private
void
dispatchTakePictureIntent() {
Intent takePictureIntent
=
new
Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if
(takePictureIntent.resolveActivity(getPackageManager()) !=
null
) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
注意這里
startActivityForResult()
方法被一個(gè)前提所保護(hù),那就是通過調(diào)用
resolveActivity()
,返回第一個(gè)可以處理該intent的組件。執(zhí)行這個(gè)檢查時(shí)很重要的因?yàn)槿绻阏{(diào)用了
startActivityForResult()
并使用一個(gè)沒有一個(gè)應(yīng)用可以處理的
intent
,你的應(yīng)用將會(huì)崩潰。所以只要結(jié)果不是
null,那么使用這個(gè)intent是安全的。
三). 獲取縮略圖
如果簡單地獲取照片不是你的應(yīng)用的終極目標(biāo),那么你可能希望從相機(jī)應(yīng)用收回圖像并做一些事情。
Android相機(jī)應(yīng)用在 onActivityResult() 中傳遞的 Intent 內(nèi),將照片編碼并作為一個(gè)小的位圖( Bitmap )在“ extras ”,在鍵“ data ”下。下面的代碼將會(huì)獲得一個(gè)圖像并在 ImageView 中顯示。
@Override
protected
void
onActivityResult(
int
requestCode,
int
resultCode, Intent data) {
if
(requestCode == REQUEST_IMAGE_CAPTURE && resultCode ==
RESULT_OK) {
Bundle extras
=
data.getExtras();
Bitmap imageBitmap
= (Bitmap) extras.get("data"
);
mImageView.setImageBitmap(imageBitmap);
}
}
Note:
這個(gè)來自“ data ”的縮略圖用作圖標(biāo)hi非常好的,但是如果用作更大的圖片就不行了。處理全尺寸的圖片需要更多操作。
四). 保存全尺寸照片
如果你提供了一個(gè)存儲文件的地方,Android相機(jī)應(yīng)用就可以存儲全尺寸的照片。你必須提供一個(gè)完整的文件名來指定相機(jī)應(yīng)用應(yīng)該把照片保存在哪里。
一般來說,任何用戶通過相機(jī)拍攝的照片都應(yīng)該存儲在設(shè)備的公共外部存儲區(qū)域,這樣他們就能被所有應(yīng)用訪問。一個(gè)合適的共享照片存儲目錄可以通過帶有 DIRECTORY_PICTURES 參數(shù)的 getExternalStoragePublicDirectory() 函數(shù)獲得。因?yàn)橛稍摲椒ㄌ峁┑哪夸浭潜凰袘?yīng)用所共享的,在目錄內(nèi)讀或?qū)懛謩e要 READ_EXTERNAL_STORAGE 和 WRITE_EXTERNAL_STORAGE 的權(quán)限聲明。寫權(quán)限隱含了讀權(quán)限,所以如果你需要寫入外部目錄,那么你只需要聲明一個(gè)權(quán)限:
<
manifest
...
>
<
uses-permission
android:name
="android.permission.WRITE_EXTERNAL_STORAGE"
/>
...
</
manifest
>
然而,如果你希望保持這些照片是你應(yīng)用私有的,那么你可以使用由
getExternalFilesDir()
提供的目錄。在Android 4.3或更低版本的系統(tǒng)中,寫入該目錄也需要
WRITE_EXTERNAL_STORAGE
權(quán)限。從Android 4.4以后,這個(gè)權(quán)限就不在需要了。因?yàn)檫@個(gè)目錄對其他應(yīng)用來說是訪問不到的,所以你可以通過使用
maxSdkVersion
字段來表明該權(quán)限聲明只對低版本有效:
<
manifest
...
>
<
uses-permission
android:name
="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion
="18"
/>
...
</
manifest
>
Note:
你存儲在由 getExternalFilesDir() 所提供的目錄內(nèi)的文件,將會(huì)在用戶刪除你的應(yīng)用時(shí)一起被刪除。
一旦你決定了文件存儲的目錄,你需要?jiǎng)?chuàng)建一個(gè)不容易重名的文件名。你可能也希望在成員變量中存儲路徑名,以備今后使用。這里是一個(gè)方法的例子,它通過時(shí)間戳為一個(gè)新照片返回一個(gè)唯一的文件名:
String mCurrentPhotoPath;
private
File createImageFile()
throws
IOException {
//
Create an image file name
String timeStamp =
new
SimpleDateFormat("yyyyMMdd_HHmmss").format(
new
Date());
String imageFileName
= "JPEG_" + timeStamp + "_"
;
File storageDir
=
Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File image
=
File.createTempFile(
imageFileName,
/*
prefix
*/
".jpg",
/*
suffix
*/
storageDir
/*
directory
*/
);
//
Save a file: path for use with ACTION_VIEW intents
mCurrentPhotoPath = "file:" +
image.getAbsolutePath();
return
image;
}
通過這種方法為照片創(chuàng)建了文件,現(xiàn)在你可以像下面這樣創(chuàng)建并激活 Intent :
static
final
in REQUEST_TAKE_PHOTO = 1
;
private
void
dispatchTakePictureIntent() {
Intent takePictureIntent
=
new
Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//
Ensure that there's a camera activity to handle the intent
if
(takePictureIntent.resolveActivity(getPackageManager()) !=
null
) {
//
Create the File where the photo should go
File photoFile =
null
;
try
{
photoFile
=
createImageFile();
}
catch
(IOException ex) {
//
Error occurred while creating the File
...
}
//
Continue only if the File was successfully created
if
(photoFile !=
null
) {
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,
Uri.fromFile(photoFile));
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
五). 將照片添加至圖庫:
當(dāng)你通過一個(gè)intent創(chuàng)建了一個(gè)照片,你應(yīng)該知道照片放置在哪里,因?yàn)槟阒付怂枰鎯υ谀睦铩ζ渌魏螒?yīng)用來說,可能最簡單的讓你照片可訪問的方法就是讓它可被系統(tǒng)的媒體提供程序( Media Provider )可被訪問。
Note:
如果你把文件存儲在了由 getExternalFilesDir() 提供的路徑,那么此時(shí)媒體掃描器
下面的方法證明了如何激活系統(tǒng)的媒體掃描器將你的照片添加至照片提供程序的數(shù)據(jù)庫,使它對Android圖庫應(yīng)用和其它應(yīng)用來說是可以訪問的。
private
void
galleryAddPic() {
Intent mediaScanIntent
=
new
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f
=
new
File(mCurrentPhotoPath);
Uri contentUri
=
Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this
.sendBroadcast(mediaScanIntent);
}
六). 解碼縮放圖像
管理多個(gè)全尺寸圖像對于有限的存儲空間來說是很復(fù)雜的。如果你發(fā)現(xiàn)你的應(yīng)用在顯示了幾幅圖片后就用盡了存儲,那么你可以通過將JPEG延展到一個(gè)記憶數(shù)組里面,它將圖片縮放至目標(biāo)View的尺寸,這樣可以大幅減小使用的動(dòng)態(tài)堆內(nèi)存。下面的代碼展示了這一技術(shù):
private
void
setPic() {
//
Get the dimensions of the View
int
targetW =
mImageView.getWidth();
int
targetH =
mImageView.getHeight();
//
Get the dimensions of the bitmap
BitmapFactory.Options bmOptions =
new
BitmapFactory.Options();
bmOptions.inJustDecodeBounds
=
true
;
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
int
photoW =
bmOptions.outWidth;
int
photoH =
bmOptions.outHeight;
//
Determine how much to scale down the image
int
scaleFactor = Math.min(photoW/targetW, photoH/
targetH);
//
Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds =
false
;
bmOptions.inSampleSize
=
scaleFactor;
bmOptions.inPurgeable
=
true
;
Bitmap bitmap
=
BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
mImageView.setImageBitmap(bitmap);
}
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

