天天看點

Android開發;教你做一個背景相機

做過相機的同學都知道,Camera需要一個SurfaceView來承載預覽的輸出流,SurfaceView的特性限制了它必須要有一個可見的View才能夠使用。

是以如果我們要做一個不可見的相機有什麼辦法呢?

初階黑科技

首先可以想到的是我們可以用一個 1*1 像素的SurfaceView來承載輸出流。又或者我們用一個透明的View來承載SurfaceView。

網上搜一下可以找到很多這個方案的實作,

但是!

這意味着但跟我們的app退出到背景的時候,Camera就不能夠拍照了!

那麼有沒有更好的解決方案呢?

當然有!

高階黑科技

此時我們要介紹一個平時用的少的類,SurfaceTexture。

Camera提供了兩個方法來設定預覽界面,分别是

public native final void setPreviewSurface(Surface surface) throws IOException;
public native final void setPreviewTexture(SurfaceTexture surfaceTexture) throws IOException;

           

當用SurfaceTexture作為預覽的輸出流承載的時候,其實是不需要一個可見的View的。

這提供了一個思路,可以在Service裡用它來實作背景拍照的功能。

如何用呢

我們假設一個需求,使用者的手機有鎖屏密碼,他的手機丢失了以後被别人嘗試用去解鎖,當然别人解鎖的話肯定會失敗,那麼我們可以在他解鎖失敗的時候啟動相機服務,然後用前置攝像頭拍照。當我們拿到拍下來的相片後就可以通過各種方式回傳給使用者了。

這種場景下我們的應用肯定不會在前台出現,是以我們隻能通過Service的方式來實作。

首先是解鎖的監聽

這部分很簡單,我們可以繼承并重寫 DeviceAdminReceiver 來實作。這是一個系統提供的用來監聽使用者密碼狀态的類,具體用法可以參考後面給出的demo。

然後是Camera

使用Camera的話都需要先擷取硬體Camera并初始化相關的參數,

這裡給出demo代碼

private Camera getCamerInstance() {
 android.hardware.Camera c = null;
 if(mCamera != null) {
 return mCamera;
 }
 int cameraNum = android.hardware.Camera.getNumberOfCameras();
 Log.d(TAG, "camera number: " + cameraNum);
 try {
 c = android.hardware.Camera.open();
 mCameraId = android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK;
 } catch (Exception e) {
 Log.e(TAG, "initiate Camera failed");
 e.printStackTrace();
 }
 return c;
}

           

然後我們需要設定一個SurfaceTexture,

mTexture = new SurfaceTexture(0);
try {
 mCamera.setPreviewTexture(mTexture);
 mCamera.startPreview();
} catch (IOException e) {
 Log.e(TAG, "initiate camera failed, e: " + e.getMessage());
}

           

之後就可以通過Camera的takePicture()來擷取相機輸出流啦~

源碼 

https://github.com/AndroidPhoenix/SilentCamera

更多Android進階技術,面試資料系統整理分享,職業生涯規劃,産品,思維,行業觀察,談天說地。可以加Android架構師群;701740775。

繼續閱讀