Ответ 1
Документация по API
В соответствии с руководство для разработчиков Android для android.hardware.Camera
, они заявляют:
Мы рекомендуем использовать новый API android.hardware.camera2 для новых приложений.
На странице с информацией о android.hardware.camera2
(см. выше) указано:
Пакет android.hardware.camera2 предоставляет интерфейс для отдельных устройств камеры, подключенных к устройству Android. Он заменяет класс устаревших камер.
Проблема
Когда вы проверите эту документацию, вы обнаружите, что реализация этих 2 API-камеры очень отличается.
Например, ориентация камеры на android.hardware.Camera
@Override
public int getOrientation(final int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
return info.orientation;
}
Versus android.hardware.camera2
@Override
public int getOrientation(final int cameraId) {
try {
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String[] cameraIds = manager.getCameraIdList();
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[cameraId]);
return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
} catch (CameraAccessException e) {
// TODO handle error properly or pass it on
return 0;
}
}
Это затрудняет переход от одного к другому и запись кода, который может обрабатывать обе реализации.
Обратите внимание, что в этом примере из одного кода мне уже пришлось обойти тот факт, что API старой программы работает с примитивами int
для идентификаторов камеры, а новый работает с объектами String
. В этом примере я быстро исправил это, используя int как индекс в новом API. Если камера возвращается не всегда в том же порядке, это уже вызовет проблемы. Альтернативный подход заключается в работе с объектами String и представлением String старых идентификаторов камеры, что, вероятно, безопаснее.
Один прочь вокруг
Теперь, чтобы обойти эту огромную разницу, вы можете реализовать интерфейс сначала и ссылаться на этот интерфейс в своем коде.
Здесь я перечислил код для этого интерфейса и 2 реализации. Вы можете ограничить реализацию тем, что вы на самом деле используете API-интерфейс камеры, чтобы ограничить объем работы.
В следующем разделе я быстро объясню, как загрузить тот или иной.
Интерфейс завершает все, что вам нужно, чтобы ограничить этот пример. У меня есть только 2 метода.
public interface CameraSupport {
CameraSupport open(int cameraId);
int getOrientation(int cameraId);
}
Теперь у вас есть класс для старого аппаратного устройства api:
@SuppressWarnings("deprecation")
public class CameraOld implements CameraSupport {
private Camera camera;
@Override
public CameraSupport open(final int cameraId) {
this.camera = Camera.open(cameraId);
return this;
}
@Override
public int getOrientation(final int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
return info.orientation;
}
}
И еще один для нового аппаратного api:
public class CameraNew implements CameraSupport {
private CameraDevice camera;
private CameraManager manager;
public CameraNew(final Context context) {
this.manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
}
@Override
public CameraSupport open(final int cameraId) {
try {
String[] cameraIds = manager.getCameraIdList();
manager.openCamera(cameraIds[cameraId], new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
CameraNew.this.camera = camera;
}
@Override
public void onDisconnected(CameraDevice camera) {
CameraNew.this.camera = camera;
// TODO handle
}
@Override
public void onError(CameraDevice camera, int error) {
CameraNew.this.camera = camera;
// TODO handle
}
}, null);
} catch (Exception e) {
// TODO handle
}
return this;
}
@Override
public int getOrientation(final int cameraId) {
try {
String[] cameraIds = manager.getCameraIdList();
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[cameraId]);
return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
} catch (CameraAccessException e) {
// TODO handle
return 0;
}
}
}
Загрузка соответствующего API
Теперь, чтобы загрузить ваш класс CameraOld
или CameraNew
, вам нужно будет проверить уровень API, поскольку CameraNew
доступен только с уровня api 21.
Если вы уже настроили инъекцию зависимостей, вы можете сделать это в своем модуле при реализации CameraSupport
. Пример:
@Module public class CameraModule {
@Provides
CameraSupport provideCameraSupport(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new CameraNew(context);
} else {
return new CameraOld();
}
}
}
Если вы не используете DI, вы можете просто сделать утилиту или использовать шаблон Factory, чтобы создать правильный. Важная часть состоит в том, что проверяется уровень API.