简体   繁体   English

Android 相机 android.hardware.Camera 已弃用

[英]Android camera android.hardware.Camera deprecated

如果不推荐使用android.hardware.Camera并且您不能使用变量Camera ,那么有什么替代方法呢?

API Documentation API 文档

According to the Android developers guide for android.hardware.Camera , they state:根据android.hardware.CameraAndroid 开发者指南,他们指出:

We recommend using the new android.hardware.camera2 API for new applications.我们建议为新应用程序使用新的android.hardware.camera2 API。

On the information page about android.hardware.camera2 , (linked above), it is stated:在关于android.hardware.camera2的信息页面上,(上面链接),它指出:

The android.hardware.camera2 package provides an interface to individual camera devices connected to an Android device. android.hardware.camera2 包为连接到 Android 设备的各个相机设备提供了一个接口。 It replaces the deprecated Camera class.它取代了已弃用的 Camera 类。

The problem问题

When you check that documentation you'll find that the implementation of these 2 Camera API's are very different.当您查看该文档时,您会发现这两个 Camera API 的实现非常不同。

For example getting camera orientation on android.hardware.camera例如在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对比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;
    }
}

This makes it hard to switch from one to another and write code that can handle both implementations.这使得很难从一个切换到另一个并编写可以处理这两种实现的代码。

Note that in this single code example I already had to work around the fact that the olde camera API works with int primitives for camera IDs while the new one works with String objects.请注意,在这个单一的代码示例中,我已经不得不解决这样一个事实,即旧的相机 API 使用用于相机 ID 的int原语,而新的使用String对象。 For this example I quickly fixed that by using the int as an index in the new API.对于这个例子,我通过在新 API 中使用 int 作为索引来快速解决这个问题。 If the camera's returned aren't always in the same order this will already cause issues.如果返回的相机并不总是按相同的顺序,这已经会导致问题。 Alternative approach is to work with String objects and String representation of the old int cameraIDs which is probably safer.替代方法是使用 String 对象和旧 int cameraID 的 String 表示,这可能更安全。

One away around一圈

Now to work around this huge difference you can implement an interface first and reference that interface in your code.现在要解决这个巨大的差异,您可以先实现一个接口并在代码中引用该接口。

Here I'll list some code for that interface and the 2 implementations.在这里,我将列出该接口的一些代码和 2 个实现。 You can limit the implementation to what you actually use of the camera API to limit the amount of work.您可以将实现限制为您实际使用的相机 API 以限制工作量。

In the next section I'll quickly explain how to load one or another.在下一节中,我将快速解释如何加载一个或另一个。

The interface wrapping all you need, to limit this example I only have 2 methods here.包装所有你需要的接口,为了限制这个例子,我这​​里只有 2 个方法。

public interface CameraSupport {
    CameraSupport open(int cameraId);
    int getOrientation(int cameraId);
}

Now have a class for the old camera hardware api:现在有一个用于旧相机硬件 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;
    }
}

And another one for the new hardware api:另一个用于新硬件 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;
        }
    }
}

Loading the proper API加载正确的 API

Now to load either your CameraOld or CameraNew class you'll have to check the API level since CameraNew is only available from api level 21.现在要加载您的CameraOldCameraNew类,您必须检查 API 级别,因为CameraNew仅可从 api 级别 21 使用。

If you have dependency injection set up already you can do so in your module when providing the CameraSupport implementation.如果您已经设置了依赖注入,则可以在提供CameraSupport实现时在您的模块中执行此操作。 Example:例子:

@Module public class CameraModule {

    @Provides
    CameraSupport provideCameraSupport(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            return new CameraNew(context);
        } else {
            return new CameraOld();
        }
    } 
}

If you don't use DI you can just make a utility or use Factory pattern to create the proper one.如果您不使用 DI,您可以制作一个实用程序或使用工厂模式来创建正确的实用程序。 Important part is that the API level is checked.重要的部分是检查 API 级别。

Faced with the same issue , supporting older devices via the deprecated camera API and needing the new Camera2 API for both current devices and moving into the future;面临同样的问题,通过已弃用的相机 API 支持旧设备,并且当前设备和未来设备都需要新的 Camera2 API; I ran into the same issues -- and have not found a 3rd party library that bridges the 2 APIs, likely because they are very different, I turned to basic OOP principals .我遇到了同样的问题——并且还没有找到桥接这两个 API 的 3rd 方库,可能是因为它们非常不同,我转向了基本的 OOP 原则

The 2 APIs are markedly different making interchanging them problematic for client objects expecting the interfaces presented in the old API.这 2 个 API 明显不同,因此对于期望旧 API 中提供的接口的客户端对象来说,交换它们是有问题的。 The new API has different objects with different methods, built using a different architecture.新的 API 有不同的对象和不同的方法,使用不同的架构构建。 Got love for Google, but ragnabbit!爱上了谷歌,但是拉格纳比特! that's frustrating.这令人沮丧。

So I created an interface focussing on only the camera functionality my app needs, and created a simple wrapper for both APIs that implements that interface.所以我创建了一个接口,只关注我的应用程序需要的相机功能,并为实现该接口的两个API 创建了一个简单的包装器。 That way my camera activity doesn't have to care about which platform its running on...这样我的相机活动就不必关心它在哪个平台上运行......

I also set up a Singleton to manage the API(s);我还设置了一个 Singleton 来管理 API; instancing the older API's wrapper with my interface for older Android OS devices, and the new API's wrapper class for newer devices using the new API.使用我的旧 Android OS 设备接口实例化旧 API 的包装器,以及使用新 API 的新设备的新 API 包装器类。 The singleton has typical code to get the API level and then instances the correct object.单例具有典型的代码来获取 API 级别,然后实例化正确的对象。

The same interface is used by both wrapper classes , so it doesn't matter if the App runs on Jellybean or Marshmallow--as long as the interface provides my app with what it needs from either Camera API, using the same method signatures;两个包装器类都使用相同的接口,因此应用程序是在 Jellybean 还是 Marshmallow 上运行并不重要——只要该接口使用相同的方法签名为我的应用程序提供它从任一相机 API 所需的内容; the camera runs in the App the same way for both newer and older versions of Android.相机在应用程序中的运行方式与新旧版本的 Android 相同。

The Singleton can also do some related things not tied to the APIs--like detecting that there is indeed a camera on the device, and saving to the media library. Singleton 还可以做一些与 API 无关的相关事情——比如检测设备上确实有一个摄像头,并保存到媒体库中。

I hope the idea helps you out.我希望这个想法可以帮助你。

Now we have to use android.hardware.camera2 as android.hardware.Camera is deprecated which will only work on API >23 FlashLight现在我们必须使用 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;
                    }


            }
        });
    }
}

Answers provided here as which camera api to use are wrong.此处提供的答案是使用哪个相机 api 是错误的。 Or better to say they are insufficient.或者更好地说它们是不够的。

Some phones (for example Samsung Galaxy S6) could be above api level 21 but still may not support Camera2 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;
}

CameraManager class in Camera2Api has a method to read camera characteristics. Camera2Api 中的 CameraManager 类具有读取相机特征的方法。 You should check if hardware wise device is supporting Camera2 Api or not.您应该检查硬件设备是否支持 Camera2 Api。

But there are more issues to handle if you really want to make it work for a serious application: Like, auto-flash option may not work for some devices or battery level of the phone might create a RuntimeException on Camera or phone could return an invalid camera id and etc.但是,如果您真的想让它适用于严肃的应用程序,还有更多问题需要处理:例如,自动闪光选项可能不适用于某些设备或手机的电池电量可能会在相机上创建 RuntimeException 或手机可能返回无效相机ID等

So best approach is to have a fallback mechanism as for some reason Camera2 fails to start you can try Camera1 and if this fails as well you can make a call to Android to open default Camera for you.所以最好的方法是有一个后备机制,因为由于某种原因 Camera2 无法启动,您可以尝试 Camera1,如果它也失败了,您可以调用 Android 为您打开默认相机。

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


 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Torch / Flashlight应用程序(不推荐使用android.hardware.camera) - Torch / Flashlight app (android.hardware.camera is deprecated) android.hardware.Camera $ EventHandler.handleMessage - android.hardware.Camera$EventHandler.handleMessage 以横向模式返回(android.hardware.Camera) - Returning (android.hardware.Camera) in landscape mode 如何检查android.hardware.Camera是否已发布? - How to check if android.hardware.Camera is released? 是否可以使用已弃用的api android.hardware.Camera访问外部USB摄像头 - Is it possible to access external usb camera using deprecated api android.hardware.Camera Android弃用了android.hardware.Camera,现在建议使用android.hardware.camera2,但这不适用于API 21以下的任何内容 - Android deprecated android.hardware.Camera and now recommend using android.hardware.camera2 but this is not available in anything below API 21 “不推荐使用android.hardware.camera”:可以将源导入项目目录吗? - “android.hardware.camera is deprecated” : Can I import the source to project directory? android.hardware.Camera 是否适用于较新版本的 android? - Does android.hardware.Camera work for newer versions of android? 尝试使用Android.Hardware.Camera拍照时出错 - Error trying to take picture with Android.Hardware.Camera android.hardware.Camera是否仍可在所有API级别上使用? - Does android.hardware.Camera still works on all API levels?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM