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


97

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



1
У меня была эта проблема с приложением, и я нашел это очень полезным. Если вы используете намерение, вы ограничены. Итак, в этом руководстве объясняется альтернатива: developer.android.com/guide/topics/media/…
Роналду Баия

Ответы:


103

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

Согласно руководству для разработчиков Androidandroid.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. Если камера возвращается не всегда в том же порядке, это уже вызовет проблемы. Альтернативный подход - работать с объектами String и строковым представлением старых int cameraID, что, вероятно, более безопасно.

Один далеко

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

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


25
Что делать, если мне нужно поддерживать уровень API Android ниже 21?
niveuseverto

1
@Angelius, возможно, эта документация поможет developer.android.com/guide/topics/media/camera.html, но это может быть отдельный вопрос или поиск вопросов о необходимости использования устаревших переменных.

@Angelius, вот некоторая информация об @SuppressWarningsэтом QA stackoverflow.com/questions/7397996/…

5
Я думаю не просто об использовании @deprecated классов, а о том, как сделать приложение с обратной совместимостью? любая официальная помощь по этому поводу? У меня есть представление об этом: интерфейс ICamera, поддерживаемый объектом Camera, соответствующим текущей версии телефона, но это немного прямолинейно и сложно поддерживать ...
niveuseverto

@Angelius то, что вы описываете, может быть отдельным вопросом (сначала проверьте, задавался ли он ранее).

5

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

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

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

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

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

Синглтон также может выполнять некоторые связанные действия, не связанные с 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
почему бы не добавить коды в комментариях прямо в ответ?
Angel 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, но по-прежнему могут не поддерживать 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, чтобы открыть для вас камеру по умолчанию.


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


 }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.