API 文档
根据Android developers guide for android.hardware.Camera,他们声明:
我们建议将新的android.hardware.camera2 API 用于新应用程序。
在关于android.hardware.camera2的信息页面(上面链接)上写着:
android.hardware.camera2 包为连接到 Android 设备的各个相机设备提供了一个接口。 它取代了已弃用的 Camera 类。
问题
当您查看该文档时,您会发现这 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;
}
与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 相机 ID 原语一起使用,而新相机 API 与 String 对象一起使用。对于这个示例,我通过在新 API 中使用 int 作为索引快速解决了这个问题。如果相机返回的顺序并不总是相同,这已经导致问题。另一种方法是使用 String 对象和旧的 int cameraIDs 的 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,您可以制作一个实用程序或使用工厂模式来创建正确的。重要的部分是检查 API 级别。