Android相机android.hardware.Camera已弃用

问题描述 投票:85回答:4

如果android.hardware.Camera被弃用而且你不能使用变量Camera,那么它的替代方案是什么呢?

android android-camera android-hardware
4个回答
94
投票

API文档

根据Android developers guideandroid.hardware.Camera,他们说:

我们建议将新的android.hardware.camera2 API用于新的应用程序。

在关于android.hardware.camera2的信息页面(上面链接)中,声明:

android.hardware.camera2包为连接到Android设备的各个相机设备提供接口。它取代了已弃用的Camera类。

问题

当您检查该文档时,您会发现这两个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);
}

现在有一个老相机硬件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

现在要加载你的CameraOldCameraNew类,你必须检查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级别。


5
投票

面对同样的问题,通过不推荐的相机API支持旧设备,并且需要新的Camera2 API用于当前设备并进入未来;我遇到了同样的问题 - 并没有找到连接2个API的第三方库,可能是因为它们非常不同,我转向基本的OOP主体。

这两个API明显不同,因此对于期望旧API中提供的接口的客户端对象来说,交换它们会产生问题。新API使用不同的体系结构,使用不同的方法构建不同的对象。得到了谷歌的爱,但ragnabbit!这令人沮丧。

因此,我创建了一个仅关注我的应用程序所需的相机功能的界面,并为实现该界面的两个API创建了一个简单的包装器。这样我的相机活动就不必关心它在哪个平台上运行......

我还设置了一个Singleton来管理API;使用我的旧Android OS设备界面实现旧API的包装器,以及使用新API的新API的新API包装器类。单例具有获取API级别的典型代码,然后实例化正确的对象。

两个包装器类都使用相同的接口,因此App在Jellybean或Marshmallow上运行并不重要 - 只要接口使用相同的方法签名为我的应用程序提供所需的Camera API;对于新旧版本的Android,相机在应用程序中的运行方式相同。

Singleton还可以做一些与API无关的相关事情 - 比如检测设备上确实有摄像头,并保存到媒体库。

我希望这个想法可以帮助你。


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;
                    }


            }
        });
    }
}

0
投票

这里提供的答案是使用相机api是错误的。或者更好地说它们不够。

有些手机(例如三星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。

但是如果你真的想让它适用于一个严肃的应用程序,还有更多问题要处理:比如,自动闪存选项可能对某些设备不起作用,或者手机的电池电量可能会在相机或手机上创建RuntimeException可能会返回无效相机ID等

所以最好的方法是有一个回退机制,因为某些原因Camera2无法启动你可以尝试Camera1,如果这也失败了你可以打电话给Android为你打开默认相机。

© www.soinside.com 2019 - 2024. All rights reserved.