注意:本頁面所述是指 Camera2 套件。除非應用程式需要 Camera2 的特定低階功能,否則建議使用 CameraX。CameraX 和 Camera2 均支援 Android 5.0 (API 級別 21) 以上版本。
許多新型 Android 裝置的前置、後或鏡頭都配備兩個以上的相機 兩側每個鏡頭都有獨特功能,例如連拍 手動控製或動作追蹤存入支票的應用程式可能只能使用 第一種後置鏡頭,社群媒體應用程式則可能預設使用 前置鏡頭,但提供使用者切換可用選項 鏡頭。裝置也能記住孩子的選擇。
本頁說明如何列出相機鏡頭及其功能,以便您 就能在應用程式中決定要採用哪種鏡頭。 下列程式碼片段會擷取所有相機的清單,並反覆進行疊代 他們可以:
try {
val cameraIdList = cameraManager.cameraIdList // may be empty
// iterate over available camera devices
for (cameraId in cameraIdList) {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING)
val cameraCapabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
// check if the selected camera device supports basic features
// ensures backward compatibility with the original Camera API
val isBackwardCompatible = cameraCapabilities?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
...
}
} catch (e: CameraAccessException) {
e.message?.let { Log.e(TAG, it) }
...
}
try {
String[] cameraIdList = cameraManager.getCameraIdList(); // may be empty
// iterate over available camera devices
for (String cameraId : cameraIdList) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
int cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
int[] cameraCapabilities =
characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
// check if the selected camera device supports basic features
// ensures backward compatibility with the original Camera API
boolean isBackwardCompatible = false;
for (int capability : cameraCapabilities) {
if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) {
isBackwardCompatible = true;
break;
}
}
...
}
} catch (CameraAccessException e) {
Log.e(TAG, e.getMessage());
...
}
cameraLensFacing
變數用於說明相機面對的方向
,且具有下列其中一個值:
CameraMetadata.LENS_FACING_FRONT
CameraMetadata.LENS_FACING_BACK
CameraMetadata.LENS_FACING_EXTERNAL
如要進一步瞭解鏡頭方向設定,請參閱
CameraCharacteristics.LENS_FACING
。
上述程式碼範例中的 cameraCapabilities
變數包含
其他功能的資訊,包括相機是否
能產生標準影格做為輸出內容 (相對於只有
深度感應器資料)。您可以檢查
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
敬上
是相機列出的其中一項功能,會在
isBackwardCompatible
。
選擇合理的預設值
您可能會想在應用程式中預設開啟特定攝影機 (如果有的話)。舉例來說,自拍應用程式可能會以前置鏡頭開啟 而擴增實境應用程式則可能是以後置鏡頭啟動。 下方函式會傳回第一個面對指定方向的鏡頭:
fun getFirstCameraIdFacing(cameraManager: CameraManager,
facing: Int = CameraMetadata.LENS_FACING_BACK): String? {
try {
// Get list of all compatible cameras
val cameraIds = cameraManager.cameraIdList.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
capabilities?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
}
// 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()
} catch (e: CameraAccessException) {
e.message?.let { Log.e(TAG, it) }
}
}
public String getFirstCameraIdFacing(CameraManager cameraManager, @Nullable Integer facing) {
if (facing == null) facing = CameraMetadata.LENS_FACING_BACK;
String cameraId = null;
try {
// Get a list of all compatible cameras
String[] cameraIdList = cameraManager.getCameraIdList();
// Iterate over the list of cameras and return the first one matching desired
// lens-facing configuration and backward compatibility
for (String id : cameraIdList) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
for (int capability : capabilities) {
if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE
&& characteristics.get(CameraCharacteristics.LENS_FACING).equals(facing)) {
cameraId = id;
break;
}
}
}
// If no camera matches the desired orientation, return the first one from the list
cameraId = cameraIdList[0];
} catch (CameraAccessException e) {
Log.e(TAG, "getFirstCameraIdFacing: " + e.getMessage());
}
return cameraId;
}
啟用切換鏡頭
許多相機應用程式都為使用者提供切換鏡頭的選項:

許多裝置都有多台鏡頭朝向相同方向的鏡頭。有些甚至有 外部 USB 攝影機。為提供使用者介面,方便使用者切換 為相機選擇第一個可用的鏡頭 。
雖然沒有通用的邏輯可以選取下一部鏡頭, 下列程式碼適用於大多數用途:
fun filterCompatibleCameras(cameraIds: Array<String>,
cameraManager: CameraManager): List<String> {
return cameraIds.filter {
val characteristics = cameraManager.getCameraCharacteristics(it)
characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)?.contains(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ?: false
}
}
fun filterCameraIdsFacing(cameraIds: List<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 = filterCompatibleCameras(cameraManager.cameraIdList, cameraManager)
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 in 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)
}
}
public List<String> filterCompatibleCameras(CameraManager cameraManager, String[] cameraIds) {
final List<String> compatibleCameras = new ArrayList<>();
try {
for (String id : cameraIds) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
int[] capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
for (int capability : capabilities) {
if (capability == CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) {
compatibleCameras.add(id);
}
}
}
} catch (CameraAccessException e) {
Log.e(TAG, "filterCompatibleCameras: " + e.getMessage());
}
return compatibleCameras;
}
public List<String> filterCameraIdsFacing(CameraManager cameraManager, List<String> cameraIds, int lensFacing) {
final List<String> compatibleCameras = new ArrayList<>();
try {
for (String id : cameraIds) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id);
if (characteristics.get(CameraCharacteristics.LENS_FACING) == lensFacing) {
compatibleCameras.add(id);
}
}
} catch (CameraAccessException e) {
Log.e(TAG, "filterCameraIdsFacing: " + e.getMessage());
}
return compatibleCameras;
}
public String getNextCameraId(CameraManager cameraManager, @Nullable String currentCameraId) {
String nextCameraId = null;
try {
// Get all front, back, and external cameras in 3 separate lists
List<String> compatibleCameraIds = filterCompatibleCameras(cameraManager, cameraManager.getCameraIdList());
List<String> backCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_BACK);
List<String> frontCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_FRONT);
List<String>externalCameras = filterCameraIdsFacing(cameraManager, compatibleCameraIds, CameraMetadata.LENS_FACING_EXTERNAL);
// The recommended order of iteration is: all external, first back, first front
List<String> allCameras = new ArrayList<>(externalCameras);
if (!backCameras.isEmpty()) allCameras.add(backCameras.get(0));
if (!frontCameras.isEmpty()) allCameras.add(frontCameras.get(0));
// Get the index of the currently selected camera in the list
int cameraIndex = allCameras.indexOf(currentCameraId);
// The selected camera may not be in the list, for example it could be an
// external camera that has been removed by the user
if (cameraIndex == -1) {
// Return the first camera from the list
nextCameraId = !allCameras.isEmpty() ? allCameras.get(0) : null;
else {
if (!allCameras.isEmpty()) {
// Return the next camera from the list, wrap around if necessary
nextCameraId = allCameras.get((cameraIndex + 1) % allCameras.size());
}
}
} catch (CameraAccessException e) {
Log.e(TAG, "getNextCameraId: " + e.getMessage());
}
return nextCameraId;
}
這個代碼適用於多種裝置,且有多種不同的
儲存空間設定如要進一步瞭解如何將極端情況納入考量,請參閱「CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
」。
建立相容的應用程式
如果應用程式仍在使用已淘汰的 Camera API,則相機數量
並
Camera.getNumberOfCameras()
敬上
會傳回 取決於原始設備製造商 (OEM) 實作。如果
為維持應用程式回溯相容性,此方法僅會公開一個
。
使用 Camera2 API 查看所有相機。
如需更多相機方向的背景資訊,請參見
Camera.CameraInfo.orientation
。
一般來說,請使用
Camera.getCameraInfo()
敬上
用於查詢所有相機的 API
orientation
,
並且只向符合以下條件的使用者顯示一部相機
切換鏡頭。
適用於所有裝置類型
請勿假設應用程式一律會在手持裝置上, 連接兩部攝影機請改為為應用程式選擇最合適的相機。如果發生以下情況: 不需要特定攝影機,請選取第一個面向所需的鏡頭 往上移動即可如果連接外接式攝影機,您可能會誤以為使用者 請用預設值將其清除。