相機使用基礎之 調用系統中的相機應用
通過Intent直接調用系統相機
直接調用系統的相機應用,只需要在Intent對象中傳入相應的參數即可,總體來說需要以下三步:
1. Compose a Camera Intent
MediaStore.ACTION_IMAGE_CAPTURE 拍照;
MediaStore.ACTION_VIDEO_CAPTURE錄像。
2. Start the Camera Intent
使用startActivityForResult()方法,並傳入上面的intent對象。
之后,系統自帶的相機應用就會啟動,用戶就可以用它來拍照或者錄像。
3. Receive the Intent Result
用onActivityResult()接收傳回的圖像,當用戶拍完照片或者錄像,或者取消后,系統都會調用這個函數。
關於接收圖像
如果不設置接收圖像的部分,拍照完畢后將會返回到原來的activity,相片會自動存儲在拍照應用的默認存儲位置。
為了接收圖像,需要做以下幾個工作:
1.指定圖像的存儲位置,一般圖像都是存儲在外部存儲設備,即SD卡上。
你可以考慮的標准的位置有以下兩個:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
這個方法返回圖像和視頻的標准共享位置,別的應用也可以訪問,如果你的應用被卸載了,這個路徑下的文件是會保留的。
為了區分,你可以在這個路徑下為你的應用創建一個子文件夾。
Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES)
這個方法返回的路徑是和你的應用相關的一個存儲圖像和視頻的方法。
如果應用被卸載,這個路徑下的東西全都會被刪除。
這個路徑沒有什么安全性限制,別的應用也可以自由訪問里面的文件。
2.為了接收intent的結果,需要覆寫activity中的 onActivityResult() 方法。
前面說過,可以不設置相機返回的圖像結果的操作,此時在startActivityForResult()中不需要給intent傳入額外的數據,這樣在onActivityResult()回調時,返回的Intent data不為null,照片存在系統默認的圖片存儲路徑下。
但是如果想得到這個圖像,你必須制定要存儲的目標File,並且把它作為URI傳給啟動的intent,使用MediaStore.EXTRA_OUTPUT作為關鍵字。
這樣的話,拍攝出來的照片將會存在這個特殊指定的地方,此時沒有thumbnail會被返回給activity的回調函數,所以接收到的Intent data為null。
程序實例
附上程序代碼,其中視頻存儲的返回結果部分沒有寫代碼,視頻拍攝后會存入系統應用的默認位置。
系統自帶相機應用測試
package com.example.hellocamera; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.Toast; public class HelloCameraActivity extends Activity { private static final String LOG_TAG = "HelloCamera"; private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100; private static final int CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE = 200; private Button takePicBtn = null; private Button takeVideoBtn = null; private ImageView imageView = null; private Uri fileUri; @Override public void onCreate(Bundle savedInstanceState) { Log.d(LOG_TAG, "onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_hello_camera); takePicBtn = (Button) findViewById(R.id.buttonPicture); takePicBtn.setOnClickListener(takePiClickListener); takeVideoBtn = (Button) findViewById(R.id.buttonVideo); takeVideoBtn.setOnClickListener(takeVideoClickListener); imageView = (ImageView) findViewById(R.id.imageView1); } private final OnClickListener takePiClickListener = new View.OnClickListener() { @Override public void onClick(View v) { Log.d(LOG_TAG, "Take Picture Button Click"); // 利用系統自帶的相機應用:拍照 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); // create a file to save the image fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); // 此處這句intent的值設置關系到后面的onActivityResult中會進入那個分支,即關系到data是否為null,如果此處指定,則后來的data為null // set the image file name intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); startActivityForResult(intent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE); } }; private final OnClickListener takeVideoClickListener = new View.OnClickListener() { @Override public void onClick(View v) { Log.d(LOG_TAG, "Take Video Button Click"); // 攝像 Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); // create a file to save the video fileUri = getOutputMediaFileUri(MEDIA_TYPE_VIDEO); // set the image file name intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); // set the video image quality to high intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); startActivityForResult(intent, CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE); } }; public static final int MEDIA_TYPE_IMAGE = 1; public static final int MEDIA_TYPE_VIDEO = 2; /** Create a file Uri for saving an image or video */ private static Uri getOutputMediaFileUri(int type) { return Uri.fromFile(getOutputMediaFile(type)); } /** Create a File for saving an image or video */ private static File getOutputMediaFile(int type) { // To be safe, you should check that the SDCard is mounted // using Environment.getExternalStorageState() before doing this. File mediaStorageDir = null; try { // This location works best if you want the created images to be // shared // between applications and persist after your app has been // uninstalled. mediaStorageDir = new File( Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "MyCameraApp"); Log.d(LOG_TAG, "Successfully created mediaStorageDir: " + mediaStorageDir); } catch (Exception e) { e.printStackTrace(); Log.d(LOG_TAG, "Error in Creating mediaStorageDir: " + mediaStorageDir); } // Create the storage directory if it does not exist if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { // 在SD卡上創建文件夾需要權限: // <uses-permission // android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> Log.d(LOG_TAG, "failed to create directory, check if you have the WRITE_EXTERNAL_STORAGE permission"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") .format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); } else if (type == MEDIA_TYPE_VIDEO) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4"); } else { return null; } return mediaFile; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); Log.d(LOG_TAG, "onActivityResult: requestCode: " + requestCode + ", resultCode: " + requestCode + ", data: " + data); // 如果是拍照 if (CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE == requestCode) { Log.d(LOG_TAG, "CAPTURE_IMAGE"); if (RESULT_OK == resultCode) { Log.d(LOG_TAG, "RESULT_OK"); // Check if the result includes a thumbnail Bitmap if (data != null) { // 沒有指定特定存儲路徑的時候 Log.d(LOG_TAG, "data is NOT null, file on default position."); // 指定了存儲路徑的時候(intent.putExtra(MediaStore.EXTRA_OUTPUT,fileUri);) // Image captured and saved to fileUri specified in the // Intent Toast.makeText(this, "Image saved to:\n" + data.getData(), Toast.LENGTH_LONG).show(); if (data.hasExtra("data")) { Bitmap thumbnail = data.getParcelableExtra("data"); imageView.setImageBitmap(thumbnail); } } else { Log.d(LOG_TAG, "data IS null, file saved on target position."); // If there is no thumbnail image data, the image // will have been stored in the target output URI. // Resize the full image to fit in out image view. int width = imageView.getWidth(); int height = imageView.getHeight(); BitmapFactory.Options factoryOptions = new BitmapFactory.Options(); factoryOptions.inJustDecodeBounds = true; BitmapFactory.decodeFile(fileUri.getPath(), factoryOptions); int imageWidth = factoryOptions.outWidth; int imageHeight = factoryOptions.outHeight; // Determine how much to scale down the image int scaleFactor = Math.min(imageWidth / width, imageHeight / height); // Decode the image file into a Bitmap sized to fill the // View factoryOptions.inJustDecodeBounds = false; factoryOptions.inSampleSize = scaleFactor; factoryOptions.inPurgeable = true; Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(), factoryOptions); imageView.setImageBitmap(bitmap); } } else if (resultCode == RESULT_CANCELED) { // User cancelled the image capture } else { // Image capture failed, advise user } } // 如果是錄像 if (requestCode == CAPTURE_VIDEO_ACTIVITY_REQUEST_CODE) { Log.d(LOG_TAG, "CAPTURE_VIDEO"); if (resultCode == RESULT_OK) { } else if (resultCode == RESULT_CANCELED) { // User cancelled the video capture } else { // Video capture failed, advise user } } } }
程序運行截圖,拍照之后返回:

參考資料
Reference: Camera:http://developer.android.com/reference/android/hardware/Camera.html
API Guides: Camera: http://developer.android.com/guide/topics/media/camera.html
