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

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

Ответ 1

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

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

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

На странице с информацией о android.hardware.camera2 (см. выше) указано:

Пакет android.hardware.camera2 предоставляет интерфейс для отдельных устройств камеры, подключенных к устройству Android. Он заменяет класс устаревших камер.

Проблема

Когда вы проверите эту документацию, вы обнаружите, что реализация этих 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;
}

Versus 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 и представлением 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

Теперь, чтобы загрузить ваш класс 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.

Ответ 2

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

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

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

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

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

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

Я надеюсь, что эта идея поможет вам.

Ответ 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;
                    }


            }
        });
    }
}