【问题标题】:Android camera android.hardware.Camera deprecatedAndroid 相机 android.hardware.Camera 已弃用
【发布时间】:2015-03-19 21:30:51
【问题描述】:

如果 android.hardware.Camera 已被弃用并且您不能使用变量 Camera,那么还有什么替代方法?

【问题讨论】:

标签: android android-camera android-hardware


【解决方案1】:

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

现在要加载您的 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 级别。

【讨论】:

  • 如果我需要支持低于21的android API级别怎么办?
  • @Angelius 也许这个文档会对developer.android.com/guide/topics/media/camera.html 有所帮助-但这可能是一个单独的问题,或者搜索有关必须使用已弃用变量的问题。
  • @Angelius 这里有一些关于@SuppressWarnings 的信息在这个QA stackoverflow.com/questions/7397996/…
  • 我在考虑的不仅仅是使用@deprecated 类,而是如何使应用程序具有向后兼容性?对此有任何官方帮助吗?我对此有想法:ICamera 接口,支持当前手机版本对应的 Camera 对象,但这有点直接且难以维护......
  • @Angelius 您所描述的可能是一个单独的问题(首先检查是否已被问过)。
【解决方案2】:

面临同样的问题,通过已弃用的相机 API 支持旧设备,并且当前设备和未来都需要新的 Camera2 API;我遇到了同样的问题——没有找到了连接这 2 个 API 的第 3 方库,可能是因为它们非常不同,我求助于基本的 OOP 主体

这 2 个 API 明显不同,因此对于期望旧 API 中提供的接口的客户端对象来说,互换它们是有问题的。新的 API 有不同的对象和不同的方法,使用不同的架构构建。爱上了 Google,但 ragnabbit!这很令人沮丧。

所以我创建了一个只关注我的应用所需的相机功能的接口,并为实现该接口的两个 API 创建了一个简单的包装器。这样我的相机活动不必关心它在哪个平台上运行......

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

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

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

我希望这个想法对你有所帮助。

【讨论】:

  • 例如:public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); }
  • ex: public interface AllCameraInterface { void open(); Bitmap takePhoto(); void close(); etc... } public class NCamera implements AllCameraInterface... public class OCamera implements AllCameraInterface... public class AllCamera { private static AllCamera ourInstance = new AllCamera(); public static AllCamera getInstance() {...} private AllCameraInterface camera; private AllCamera() { if (android.os.Build.VERSION.SDK_INT <= 20) { camera = new OCamera(); } else { camera = new NCamera(); } } 然后一个方法返回它...
  • 显然 cmets 中不允许换行 ;-) 但它确实有效。
  • 为什么不将 cmets 中的代码直接附加到答案中?
  • @RobertSherman 嗨罗伯特,你能帮我为新的camera2 重新编写这个小小的 sn-p 吗?我真的很困惑......我只需要enableAutofocus方法来打开相机并设置它的焦点:stackoverflow.com/questions/19076316/…
【解决方案3】:

现在我们必须使用 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;
                    }


            }
        });
    }
}

【讨论】:

    【解决方案4】:

    此处提供的关于使用哪个相机 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 为您打开默认相机。

    【讨论】:

      【解决方案5】:
       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();
                 }
      
      
       }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-21
        • 1970-01-01
        • 2012-12-25
        • 2021-08-31
        • 2015-09-18
        • 2018-02-11
        相关资源
        最近更新 更多