概述
在做Android開發(fā)中還是會經常選擇照片然后做上傳操作的。但是其中選擇照片系統(tǒng)的有兩種方式,第一種是拍照、第二種是從相冊中選擇。這里分別介紹下。
其中拍照有兩種方法,從系統(tǒng)相冊選擇有兩種方法,會分別介紹和分析。
拍照獲取照片的方法
剛才說過會介紹兩種方法,其實無論幾種方法原理都是一個。就是通過intent發(fā)出隱式意圖調用系統(tǒng)的照相機,然后在獲取到從相機返回的圖片,這里的兩種主要是返回方式有兩種。
1、直接返回圖片。
2、提前創(chuàng)建好存放圖片的Uri然后拍照返回后存儲起來。
第一種拍照方法:
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, TAKE_PHOTO_REQUEST);
沒錯,簡單的兩行代碼就可以調取攝像頭進行拍照了,這時候我們是通過Intent指定activion: MediaStore.ACTION_IMAGE_CAPTURE去查找符合條件的程序。相機里面會對這個action做處理,這一步屬于intent的操作了,這里不再贅述。
case TAKE_PHOTO_REQUEST:
if (resultCode == RESULT_CANCELED) {
Toast.makeText(MainActivity.this, "取消了拍照", Toast.LENGTH_LONG).show();
return;
}
Bitmap photo = data.getParcelableExtra("data");
iv_image.setImageBitmap(photo);
break;
上面的代碼是onActivityResult中的處理,判斷request后做拍照返回處理,其中data直接返回Bitmap,不過這里要注意一點就是,這個Bitmap會經過系統(tǒng)壓縮。所以有時候可能看起來照片并沒有那么清晰。也正是由于是系統(tǒng)壓縮的原因,這個圖片基本不會很大,基本不會OOM。
第二種拍照獲取照片方法:
第二種方法其實也是一樣的,只不過我們事先定義好uri,然后圖片會存儲到這個uri中,然后我們可以通過這個uri在本地找到具體的圖片,然后做處理,展示。
private static Uri createImageUri(Context context) {
String name = "takePhoto" + System.currentTimeMillis();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.TITLE, name);
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, name + ".jpeg");
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
return uri;
}
上述代碼是創(chuàng)建一個uri用來存儲拍照后的照片。
public static void delteImageUri(Context context, Uri uri) {
context.getContentResolver().delete(uri, null, null);
}
上述代碼是用來刪除一個本地uri
btn_take_photo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
imageUri = createImageUri(MainActivity.this);
Intent intent = new Intent();
intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//如果不設置EXTRA_OUTPUT getData() 獲取的是bitmap數據 是壓縮后的
startActivityForResult(intent, TAKE_PHOTO_REQUEST_ONE);
}
});
然后通過上述代碼創(chuàng)建imageUri然后發(fā)起拍照,方式同樣用Intent,可參第一種方法。
if (resultCode == RESULT_CANCELED) {
delteImageUri(MainActivity.this,imageUri);
return;
}
case TAKE_PHOTO_REQUEST_ONE:
iv_image.setImageURI(imageUri);
break;
最后就是獲取拍照的照片做處理或者顯示。
其中如果取消的話就刪除創(chuàng)建的rui。
Bitmap bitmap=MediaStore.Images.Media.getBitmap(getContentResolver(),imageUri);
iv_image.setImageBitmap(bitmap);
還可以直接通過MediaStore獲取bitmap進行設置。
以上方法經測試在可以正常獲取照片。
但是這樣還會有個問題,就是如果圖片過大的情況下,會有異常。
W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (3120x4208, max=4096x4096)
如上代碼所示,會直接報bitmap的過大而無法顯示圖片。
第一種處理方法就是對圖片進行處理。
這里介紹第二種處理方式,就是用不同的方式去創(chuàng)建存儲圖片的文件。
public class TakePhotoUtils {
/**
* 拍照
*/
public static Uri takePhoto(Activity mActivity, int flag) throws IOException {
//指定拍照intent
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri imageUri = null;
if (takePictureIntent.resolveActivity(mActivity.getPackageManager()) != null) {
String sdcardState = Environment.getExternalStorageState();
File outputImage = null;
if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {
outputImage = createImageFile(mActivity);
} else {
Toast.makeText(mActivity.getApplicationContext(), "內存異常", Toast.LENGTH_SHORT).show();
}
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (outputImage != null) {
imageUri = Uri.fromFile(outputImage);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
mActivity.startActivityForResult(takePictureIntent, flag);
}
}
return imageUri;
}
public static File createImageFile(Activity mActivity) throws IOException {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
String imageFileName = "JPEG_" + timeStamp;//創(chuàng)建以時間命名的文件名稱
File storageDir = getOwnCacheDirectory(mActivity, "takephoto");//創(chuàng)建保存的路徑
File image = new File(storageDir.getPath(), imageFileName + ".jpg");
if (!image.exists()) {
try {
//在指定的文件夾中創(chuàng)建文件
image.createNewFile();
} catch (Exception e) {
}
}
return image;
}
/**
* 根據目錄創(chuàng)建文件夾
* @param context
* @param cacheDir
* @return
*/
public static File getOwnCacheDirectory(Context context, String cacheDir) {
File appCacheDir = null;
//判斷sd卡正常掛載并且擁有權限的時候創(chuàng)建文件
if ( Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
}
if (appCacheDir == null || !appCacheDir.exists() && !appCacheDir.mkdirs()) {
appCacheDir = context.getCacheDir();
}
return appCacheDir;
}
/**
* 檢查是否有權限
* @param context
* @return
*/
private static boolean hasExternalStoragePermission(Context context) {
int perm = context.checkCallingOrSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE");
return perm == 0;
}
}
代碼沒什么難點,簡單寫了一個工具類,里面封裝了一個拍照的方法,并返回一個存儲拍照后的路徑。
路徑是自己制定文件夾后創(chuàng)建一個文件,用于存儲照片。文件名是根據時間命名的,以免重復。
if (resultCode == RESULT_CANCELED) {
Toast.makeText(MainActivity.this, "點擊取消從相冊選擇", Toast.LENGTH_LONG).show();
return;
}
Bitmap bitmap = BitmapFactory.decodeFile(imageUri.getPath(), getOptions(imageUri.getPath()));
iv_image.setImageBitmap(bitmap);
然后在onActivityResult的方法中進行處理,這里也最好對圖片進行下壓縮處理。然后就可以正常顯示拍照后的圖片了。
/**
* 獲取壓縮圖片的options
*
* @return
*/
public static BitmapFactory.Options getOptions(String path) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inSampleSize = 4; //此項參數可以根據需求進行計算
options.inJustDecodeBounds = false;
return options;
}
這里的只是簡單的處理方法,按照指定參數壓縮下,這里的inSapleSizes是需要根據自己需求進行算法的。
這樣基本就可以通過拍照來獲取照片了
從相冊選擇照片來展示
其實拍照主要也是通過intent來調用系統(tǒng)相冊,然后通過返回數據在onActivityResult中進行處理。
public void pickImageFromAlbum() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, 111);
}
public void pickImageFromAlbum2() {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_PICK);
intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 222);
}
如圖兩種方式均可以調用系統(tǒng)相冊進行選擇照片。
if (resultCode == RESULT_CANCELED) {
Toast.makeText(MainActivity.this, "點擊取消從相冊選擇", Toast.LENGTH_LONG).show();
return;
}
try {
Uri imageUri = data.getData();
Log.e("TAG", imageUri.toString());
iv_image.setImageURI(imageUri);
} catch (Exception e) {
e.printStackTrace();
}
然后返回的處理方式基本是一樣的 拿到uri后進行對圖片處理就好了。這里說明下如果圖片過大可能也需要進行二次處理。
如本篇有錯誤歡迎大家留言指正。