本例介紹了如何使用裝置的網路攝影機來預覽將要拍攝的照片,本例需要真實的手機來運行:
例子中用到兩個方面的知識:SurfaceView 和android.hardware.Camera。
SurfaceView 為View的子類,它提供一個專門用於繪圖的Surface,目的是允許使用背景工作執行緒中這個Surface上繪圖,這樣對於應費時的繪圖操作無需放在UI線程中,而是可以在單獨的背景工作執行緒中按照自己的節奏來繪圖。
使用SurfaceView時需要從SurfaceView派生一個子類,這個子類需要實現SurfaceHolder.Callback介面,這個介面提供了幾個回呼函數用於通知應用關於Surface的訊息,如什麼時候建立,改變大小,銷毀等。實現這些回呼函數非常重要,應用可以在這些回呼函數來調整Surface的一些說明,知道何時可以在Surface繪製等。通常在這個SurfaceView的衍生類別中會定義一個背景工作執行緒用於繪圖。
在Surface上繪圖時,不是通過直接的函數調用,而是通過擷取Surface控制代碼(SurfaceHolder)的間接方法.因此在Surface初始化時,調用getHolder()來擷取Surface的控制代碼。通常是在擷取SurfaceHolder之後,再調用mHolder.addCallback(this)來響應SurfaceHolder.Callback事件。
如何使用背景工作執行緒中Surface 的Canvas上繪製圖形本例沒有涉及,將在後面的例子說明。
下面代碼定義了SurfaceView子類並實現SurfaceHolder.Callback介面。
[java]
class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;
Camera mCamera;
...
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the
// camera and tell it where
// to draw.
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
// TODO: add more exception handling logic here
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return,
// so stop the preview.
// Because the CameraDevice object is not a
//shared resource, it's very
// important to release it when the activity is paused.
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder,
int format, int w, int h) {
// Now that the size is known, set up the
//camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, w, h);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
class Preview extends SurfaceView implements SurfaceHolder.Callback {
SurfaceHolder mHolder;
Camera mCamera;
...
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the
// camera and tell it where
// to draw.
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
// TODO: add more exception handling logic here
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return,
// so stop the preview.
// Because the CameraDevice object is not a
//shared resource, it's very
// important to release it when the activity is paused.
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void surfaceChanged(SurfaceHolder holder,
int format, int w, int h) {
// Now that the size is known, set up the
//camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
List<Size> sizes = parameters.getSupportedPreviewSizes();
Size optimalSize = getOptimalPreviewSize(sizes, w, h);
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
Camera 這裡使用的Camera類是定義在android.hardware包中代表的是網路攝影機硬體裝置,Camera類可以用來設定裝置網路攝影機的配置,開始/停止預覽,拍照或是視頻。這個類是Camera服務(用來管理實際裝置的服務)的用戶端。
為了能使用裝置的網路攝影機,必須在AndroidManifest.xml中定義對應的許可權permission和uses-feature如下:
<uses-permission android:name=”android.permission.CAMERA” />
<uses-feature android:name=”android.hardware.camera” />
<uses-feature android:name=”android.hardware.camera.autofocus” android:required=”false” />
使用Camera拍照的一般步驟如下:
調用open(int)擷取一個Camera的樣本對象.
使用getParameters()擷取Camera 的預設配置參數.
如果有需要,調用setParameters(Camera.Parameters)修改Camera的參數.
如果有需要,可以調用setDisplayOrientation(int)設定取景為縱向或是橫向。
將一個初始化過的SurfaceHolder通過setPreviewDisplay(SurfaceHolder),如果沒有指定Surface,Camera將無法開始預覽。
調用startPreview()開始畫面預覽,拍照之前必須先開始預覽。
如需拍照可以調用takePicture(Camera.ShutterCallback, Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback),拍照完成事件將以回呼函數的方式通知應用。
拍照完成時,Camera自動停止預覽狀態,需調用startPreview來拍新的照片。
調用stopPreview()停止預覽。
最後不在使用Camera調用release()釋放資源以便其它應用可以使用Camera。
作者:mapdigit