如果不推荐使用android.hardware.Camera
并且您无法使用变量Camera
,那么替代它的是什么?
答案 0 :(得分:92)
根据android.hardware.Camera
的{{3}},他们声明:
我们建议您为新应用程序使用新的Android developers guide API。
在关于android.hardware.camera2
的信息页面(上面已链接)中,声明:
android.hardware.camera2包为连接到Android设备的各个相机设备提供了一个界面。 它取代了已弃用的Camera类。
当您检查该文档时,您会发现这两个相机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;
}
}
这使得很难从一个切换到另一个并编写可以处理这两种实现的代码。
请注意,在这个单独的代码示例中,我已经不得不解决这样一个事实:olde相机API使用int
基元来处理相机ID,而新的适用于String
个对象。对于这个例子,我通过在新API中使用int作为索引来快速修复它。如果相机返回的内容总是处于相同的顺序,则会导致问题。另一种方法是使用String对象和旧int cameraIDs的String表示,这可能更安全。
现在要解决这个巨大的差异,您可以先实现一个接口,然后在代码中引用该接口。
在这里,我将列出该接口和2个实现的一些代码。您可以将实现限制为您实际使用相机API的内容,以限制工作量。
在下一节中,我将快速解释如何加载其中一个或另一个。
包装所有你需要的界面,为了限制这个例子我在这里只有2个方法。
public interface CameraSupport {
CameraSupport open(int cameraId);
int getOrientation(int cameraId);
}
现在有一个老相机硬件类的课程:
@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;
}
}
}
现在要加载您的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级别。
答案 1 :(得分:5)
面临同样的问题,通过弃用的相机API支持旧设备,并且需要新的Camera2 API用于当前设备并进入未来;我遇到了同样的问题 - 并且没有找到了连接2个API的第三方库,可能是因为它们非常不同,我转向基本的OOP主体。
2个API明显不同,因为对于期望旧API中提供的接口的客户端对象来说,交换它们会产生问题。新API使用不同的体系结构,使用不同的方法构建不同的对象。得到了谷歌的爱,但ragnabbit!这令人沮丧。
所以我创建了一个仅关注我的应用程序所需的相机功能的界面,并为两个 API创建了一个简单的包装器来实现该界面。这样我的相机活动不必关心它在哪个平台上运行...
我还设置了一个Singleton来管理API;使用我的旧Android OS设备界面实现旧API的包装器,以及使用新API的新API的新API包装器类。单例具有获取API级别的典型代码,然后实例化正确的对象。
两个包装类使用相同的接口,因此无论App在Jellybean还是Marshmallow上运行都没关系 - 只要界面为我的应用程序提供了它所需的内容Camera API,使用相同的方法签名;对于新旧版本的Android,相机在应用程序中的运行方式相同。
Singleton还可以做一些与API无关的相关事情 - 比如检测设备上确实有摄像头,并保存到媒体库。
我希望这个想法会帮助你。
答案 2 :(得分:0)
现在我们必须使用android.hardware.camera2作为android.hardware.Camera已弃用,只适用于API> 23 FlashLight
public class MainActivity extends AppCompatActivity {
Button button;
Boolean light=true;
CameraDevice cameraDevice;
private CameraManager cameraManager;
private CameraCharacteristics cameraCharacteristics;
String cameraId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button)findViewById(R.id.button);
cameraManager = (CameraManager)
getSystemService(Context.CAMERA_SERVICE);
try {
cameraId = cameraManager.getCameraIdList()[0];
} catch (CameraAccessException e) {
e.printStackTrace();
}
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(light){
try {
cameraManager.setTorchMode(cameraId,true);
} catch (CameraAccessException e) {
e.printStackTrace();
}
light=false;}
else {
try {
cameraManager.setTorchMode(cameraId,false);
} catch (CameraAccessException e) {
e.printStackTrace();
}
light=true;
}
}
});
}
}
答案 3 :(得分:0)
此处提供的使用哪种相机API的答案是错误的。或者说它们不足。
某些手机(例如Samsung Galaxy S6)可能高于api级别21,但可能仍不支持Camera2 api。
CameraCharacteristics mCameraCharacteristics = mCameraManager.getCameraCharacteristics(mCameraId);
Integer level = mCameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
if (level == null || level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
return false;
}
Camera2Api中的CameraManager类具有读取相机特征的方法。您应该检查硬件智能设备是否支持Camera2 Api。
但是,如果您真的想使其适用于严重的应用程序,则有更多的问题需要处理:例如,自动闪光选项可能不适用于某些设备,或者手机的电池电量可能会在Camera或手机上创建RuntimeException返回无效的相机ID等。
所以最好的方法是使用后备机制,因为某些原因,Camera2无法启动,您可以尝试Camera1;如果失败,您也可以致电Android为您打开默认的Camera。
答案 4 :(得分:0)
if ( getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
CameraManager cameraManager=(CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId = cameraManager.getCameraIdList()[0];
cameraManager.setTorchMode(cameraId,true);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}