Android-камера android.hardware.Camera устарела

если android.hardware.Camera устарело и вы не можете использовать переменную Camera, то что может быть альтернативой этому?


person raja121    schedule 21.01.2015    source источник
comment
android.hardware.camera2   -  person ozbek    schedule 21.01.2015
comment
У меня была эта проблема с приложением, и я нашел это очень полезным. Если вы используете намерение, вы ограничены. Итак, в этом руководстве объясняется альтернатива: developer.android.com/guide /topics/media/   -  person Ronaldo Bahia    schedule 10.03.2016


Ответы (4)


Документация API

Согласно руководству для разработчиков Android для android.hardware.Camera, они утверждают:

Мы рекомендуем использовать новый API android.hardware.camera2. для новых приложений.

На информационной странице о 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;
    }
}

Это затрудняет переключение с одного на другое и написание кода, который может работать с обеими реализациями.

Обратите внимание, что в этом единственном примере кода мне уже приходилось обходить тот факт, что старый API камеры работает с int примитивами для идентификаторов камеры, а новый работает с String объектами. В этом примере я быстро исправил это, используя int в качестве индекса в новом API. Если возвращаемые камеры не всегда в одном и том же порядке, это уже вызовет проблемы. Альтернативный подход заключается в работе со строковыми объектами и строковым представлением старых идентификаторов камеры int, что, вероятно, более безопасно.

Один далеко вокруг

Теперь, чтобы обойти эту огромную разницу, вы можете сначала реализовать интерфейс и ссылаться на этот интерфейс в своем коде.

Здесь я перечислю некоторый код для этого интерфейса и 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

Теперь, чтобы загрузить класс 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, вы можете просто создать утилиту или использовать шаблон Factory, чтобы создать правильный. Важной частью является то, что уровень API проверяется.

person Community    schedule 21.01.2015
comment
Что делать, если мне нужно поддерживать уровень Android API ниже 21? - person niveuseverto; 10.02.2015
comment
@Angelius, возможно, эта документация поможет developer.android.com/guide/topics /media/camera.html — но это может быть отдельный вопрос или поиск вопросов о необходимости использования устаревших переменных. - person ; 10.02.2015
comment
@Angelius, вот некоторая информация о @SuppressWarnings в этом QA в android"> stackoverflow.com/questions/7397996/ - person ; 10.02.2015
comment
Я думаю не только об использовании классов @deprecated, но и о том, как сделать приложение с обратной совместимостью? любая официальная помощь по этому поводу? У меня есть идея об этом: интерфейс ICamera, который поддерживается объектом Camera, соответствующим текущей версии телефона, но это немного прямолинейно и сложно поддерживать... - person niveuseverto; 13.02.2015
comment
@Angelius то, что вы описываете, может быть отдельным вопросом (проверьте, не задавался ли он раньше). - person ; 13.02.2015
comment
Есть ли успех @Angelius? - person c0dehunter; 15.04.2016
comment
Привет, ребята, у меня есть старый код, чтобы открыть камеру и установить параметр фокусировки. Неужели больше нет такого простого метода .open()? Нужен ли мне теперь CameraManager? - person ; 13.06.2017
comment
Неверный метод ProvideCameraSupport. Некоторым устройствам с уровнем API выше 21 может потребоваться работа с API камеры 1. INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY это также следует проверить. - person Oguz Ozcan; 21.03.2019
comment
Google выпустил CameraX как часть Android Jetpack, что сделало все намного проще. - person Lee Boon Kong; 14.10.2019

Столкнулись с той же проблемой, поддерживая старые устройства через устаревший API камеры и нуждаясь в новом API Camera2 как для текущих устройств, так и в будущем; Я столкнулся с теми же проблемами и не нашел стороннюю библиотеку, которая связывала бы два API, вероятно, потому, что они очень разные, я обратился к основным принципам ООП.

Два API заметно различаются, что затрудняет их замену для клиентских объектов, ожидающих интерфейсы, представленные в старом API. В новом API есть разные объекты с разными методами, построенные с использованием другой архитектуры. Есть любовь к Google, но сброд! это расстраивает.

Поэтому я создал интерфейс, ориентированный только на функции камеры, которые нужны моему приложению, и создал простую оболочку для обоих API, реализующих этот интерфейс. Таким образом, моя активность камеры не нужно заботиться о том, на какой платформе он работает...

Я также настроил Singleton для управления API; создание экземпляра оболочки старого API с моим интерфейсом для старых устройств с ОС Android и класса-оболочки нового API для более новых устройств, использующих новый API. Синглтон имеет типичный код для получения уровня API, а затем создает правильный объект.

Один и тот же интерфейс используется обоими классами-оболочками, поэтому не имеет значения, работает ли приложение на Jellybean или Marshmallow — до тех пор, пока интерфейс предоставляет моему приложению то, что ему нужно, из API камеры, использование тех же сигнатур метода; камера работает в приложении одинаково как для новых, так и для старых версий Android.

Синглтон также может выполнять некоторые связанные действия, не привязанные к API, например определять, что на устройстве действительно есть камера, и сохранять в медиатеку.

Надеюсь, идея вам поможет.

person Robert Sherman    schedule 16.06.2016
comment
Например: public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); } - person Robert Sherman; 16.06.2016
comment
пример: 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(); } } Затем метод, чтобы вернуть его... - person Robert Sherman; 16.06.2016
comment
очевидно, в комментариях не разрешены разрывы строк ;-), но это действительно работает. - person Robert Sherman; 16.06.2016
comment
почему бы не добавить коды в комментариях прямо в ответ? - person Angel Koh; 17.06.2016
comment
@RobertSherman Привет, Роберт, не могли бы вы помочь мне переписать этот крошечный фрагмент для нового camera2? Я действительно запутался... Мне просто нужен метод enableAutofocus, чтобы открыть камеру и установить ее фокус: stackoverflow.com/questions/19076316/ - person ; 13.06.2017

Теперь мы должны использовать 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;
                    }


            }
        });
    }
}
person abhay rastogi Codeblended    schedule 20.06.2017

Ответы, представленные здесь в качестве API-интерфейса камеры, неверны. Или, лучше сказать, их недостаточно.

Некоторые телефоны (например, Samsung Galaxy S6) могут иметь уровень API выше 21, но по-прежнему могут не поддерживать API Camera2.

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 в Camera2Api имеет метод для чтения характеристик камеры. Вы должны проверить, поддерживает ли аппаратное устройство Camera2 Api или нет.

Но есть и другие проблемы, которые нужно решить, если вы действительно хотите, чтобы это работало для серьезного приложения: например, опция автоматической прошивки может не работать для некоторых устройств, или уровень заряда батареи телефона может создать RuntimeException на камере, или телефон может вернуть недопустимый идентификатор камеры и т. д.

Поэтому лучший подход — иметь резервный механизм, поскольку по какой-то причине Camera2 не запускается, вы можете попробовать Camera1, и если это также не удается, вы можете позвонить в Android, чтобы открыть для вас камеру по умолчанию.

person Oguz Ozcan    schedule 21.03.2019