不建议使用Android相机android.hardware.Camera


97

如果android.hardware.Camera已弃用,并且您不能使用该变量Camera,那么对此有什么选择?



1
我在应用程序中遇到了这个问题,发现这很有帮助。如果您使用意图,那么您将受到限制。因此,本教程介绍了另一种方法:developer.android.com/guide/topics/media/…–
罗纳尔多·巴伊亚

Answers:


102

API文档

按照Android开发指南android.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;
    }
}

这使得很难从一个切换到另一个并编写可以处理这两种实现的代码。

请注意,在这个单一代码示例中,我已经不得不解决以下事实:旧相机API与int相机ID的原语一起使用,而新相机API 与String对象一起使用。对于此示例,我通过使用int作为新API中的索引来快速修复了该问题。如果返回的相机并非总是以相同的顺序,这将已经引起问题。另一种方法是使用String对象和旧的int cameraID的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,则可以制作一个实用程序或使用Factory模式创建适当的实用程序。重要的是要检查API级别。


25
如果我需要支持小于21的android API级别怎么办?
niveuseverto

1
@Angelius也许该文档对developer.android.com/guide/topics/media/camera.html有所帮助 -但这可以是一个单独的问题,也可以搜索有关必须使用不推荐使用的变量的问题。

@Angelius这里是有关的一些信息@SuppressWarnings在这个QA stackoverflow.com/questions/7397996/...

5
我不仅考虑使用@deprecated类,还考虑如何使应用程序具有向后兼容性?任何官方帮助吗?我对此有一个想法:ICamera接口,该接口支持当前手机版本上对应的Camera对象,但这有点直截了当且难以维护……
niveuseverto 2015年

@Angelius所描述的内容可能是一个单独的问题(请检查是否先问过该问题)。

5

面临相同的问题,即通过不赞成使用的相机API支持较旧的设备,并且需要新的Camera2 API既适用于当前设备,也适用于未来的设备;我遇到了同样的问题-并没有找到桥接两个API的第三方库,可能是因为它们之间的差异很大,所以我转向了基本的OOP主体

这两个API显着不同,使得交换它们对于希望使用旧API中提供接口的客户端对象来说是个难题。新API具有使用不同体系结构构建的具有不同方法的不同对象。得到了谷歌的爱,但兔子!真令人沮丧。

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

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

两个包装器类都使用相同的接口,因此无论该应用程序在Jellybean还是棉花糖上运行都没有关系-只要该接口使用相同的方法签名为我的应用程序提供任何Camera API所需的内容;相机在应用程序中的运行方式与新版和旧版Android相同。

Singleton还可以执行一些与API无关的相关操作-例如检测设备上确实存在摄像头,然后将其保存到媒体库。

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


例如:public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); }
罗伯特·谢尔曼

例如: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(); } }然后是一种返回它的方法...
罗伯特·谢尔曼

显然,注释中不允许使用换行符;-),但确实有效。
罗伯特·谢尔曼

4
为什么不将注释中的代码直接添加到答案中?
天使Koh

@RobertSherman嗨,罗伯特,您能帮我重新编写一下这个小片段camera2吗?我真的很迷茫......我只是需要enableAutofocus方法来打开摄像头,并设置其重点:stackoverflow.com/questions/19076316/...

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的答案是错误的。或者说它们不足。

某些手机​​(例如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。


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


 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.