- 原文地址:Camera Enumeration on Android
- 原文做者:Oscar Wahltinez
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:luoqiuyu
- 校對者:hanliuxin5
從 Android P 開始,添加了對邏輯多攝像頭和 USB 攝像頭的支持。這對 Android 開發者來講意味着什麼?html
一臺設備有多個攝像頭沒什麼新鮮的,可是直到如今,Android 設備仍然最多隻有先後兩個攝像頭。若是你想要打開第一個攝像頭,須要進行如下操做:前端
val cameraDevice = Camera.open(0)
複製代碼
可是這些是比較簡單的操做。現在多攝像頭意味着前置或者後置有兩個及兩個以上的攝像頭。有不少鏡頭可供選擇!android
因爲兼容性問題,儘管舊的 Camera API 已經被廢棄很長時間,上述的代碼仍然有效。可是隨着生態系統的發展,須要更先進的相機功能。所以,Android 5.0(Lollipop)引進了 Camera2,適用於 API 21 及以上。用 Camera2 API 來打開第一個存在的攝像頭代碼以下所示:ios
val cameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val cameraId = cameraManager.cameraIdList[0]
cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
override fun onOpened(device: CameraDevice) {
// Do something with `device`
}
override fun onDisconnected(device: CameraDevice) {
device.close()
}
override fun onError(device: CameraDevice, error: Int) {
onDisconnected(device)
}
}, null)
複製代碼
上述代碼目前看起來沒什麼問題。若是咱們所須要的只是一個可以打開第一個存在的攝像頭的應用程序,那麼它在大部分的 Android 手機上都有效。可是考慮到如下場景:git
那麼咱們應該怎麼作?檢查攝像頭列表和攝像頭特性:github
val cameraIdList = cameraManager.cameraIdList // may be empty
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
複製代碼
變量 cameraLensFacing
有如下取值:後端
更多有關攝像頭配置的信息,請查看文檔.bash
根據應用程序的使用狀況,咱們但願默認打開特定的相機鏡頭配置(若是能夠提供這樣的功能)。好比,自拍應用程序極可能想要打開前置攝像頭,而一款加強現實類的應用程序應該但願打開後置攝像頭。咱們能夠將這樣的一個邏輯包裝成一個函數,它能夠正確地處理上面提到的狀況:ide
fun getFirstCameraIdFacing(cameraManager: CameraManager,
facing: Int = CameraMetadata.LENS_FACING_BACK): String? {
val cameraIds = cameraManager.cameraIdList
// Iterate over the list of cameras and return the first one matching desired
// lens-facing configuration
cameraIds.forEach {
val characteristics = cameraManager.getCameraCharacteristics(it)
if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) {
return it
}
}
// If no camera matched desired orientation, return the first one from the list
return cameraIds.firstOrNull()
}
複製代碼
目前爲止,咱們討論瞭如何基於應用程序的用途選擇默認攝像頭。不少相機應用程序還爲用戶提供切換攝像頭的功能:函數
Google 相機應用中切換攝像頭按鈕
要實現這個功能,嘗試從CameraManager.getCameraIdList()提供的列表中選擇下一個攝像頭,可是這並非個好的方式。由於從 Android P 開始,咱們將會看到在一樣的狀況下更多的設備有多個攝像頭,甚至有經過 USB 鏈接的外部攝像頭。若是咱們想要提供給用戶切換不一樣攝像頭的 UI,建議(按照文檔)是爲每一個可能的鏡頭配置選擇第一個可用的攝像頭。
儘管沒有一個通用的邏輯能夠用來選擇下一個攝像頭,可是下述代碼適用於大部分狀況:
fun filterCameraIdsFacing(cameraIds: Array<String>, cameraManager: CameraManager,
facing: Int): List<String> {
return cameraIds.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
characteristics.get(CameraCharacteristics.LENS_FACING) == facing
}
}
fun getNextCameraId(cameraManager: CameraManager, currCameraId: String? = null): String? {
// Get all front, back and external cameras in 3 separate lists
val cameraIds = cameraManager.cameraIdList
val backCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_BACK)
val frontCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_FRONT)
val externalCameras = filterCameraIdsFacing(
cameraIds, cameraManager, CameraMetadata.LENS_FACING_EXTERNAL)
// The recommended order of iteration is: all external, first back, first front
val allCameras = (externalCameras + listOf(
backCameras.firstOrNull(), frontCameras.firstOrNull())).filterNotNull()
// Get the index of the currently selected camera in the list
val cameraIndex = allCameras.indexOf(currCameraId)
// The selected camera may not be on the list, for example it could be an
// external camera that has been removed by the user
return if (cameraIndex == -1) {
// Return the first camera from the list
allCameras.getOrNull(0)
} else {
// Return the next camera from the list, wrap around if necessary
allCameras.getOrNull((cameraIndex + 1) % allCameras.size)
}
}
複製代碼
這看起來可能有點複雜,可是咱們須要考慮到大量的有不一樣配置的設備。
對於那些仍然在使用已經廢棄的 Camera API 的應用程序,經過 Camera.getNumberOfCameras() 獲得的攝像頭的數量取決於 OEM 的實現。文檔上是這樣描述的:
若是系統中有邏輯多攝像頭,爲了保持應用程序的向後兼容性,這個方法僅爲每一個邏輯攝像頭和底層的物理攝像頭組公開一個攝像頭。使用 camera2 API 去查看全部攝像頭。
請仔細閱讀 其他文檔 得到更多信息。一般來講,相似的建議適用於:使用 Camera.getCameraInfo() API 查詢全部的攝像頭方向, 在用戶切換攝像頭時,僅僅只爲每一個可用的方向提供一個攝像頭。
Android 運行在許多不一樣的設備上。你不該該假設你的應用程序老是在有一兩個攝像頭的傳統的手持設備上運行,而是應該爲你的應用程序選擇最適合的攝像頭。若是你不須要特定的攝像頭,選擇有所需默認配置的第一個攝像頭。若是設備鏈接了外部攝像頭,則能夠合理的假設用戶但願首先看到這些外部攝像頭中的第一個。
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。