Камера Android android.hardware.Camera застаріла


97

якщо android.hardware.Cameraзастаріла і ви не можете використовувати цю змінну Camera, то що б було альтернативою цьому?



1
У мене була проблема з додатком, і це було дуже корисно. Якщо ви використовуєте наміри, ви обмежені. Тож у цьому підручнику пояснюється альтернатива: developer.android.com/guide/topics/media/…
Роналду Бахія

Відповіді:


102

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

Згідно з посібником для розробників Androidandroid.hardware.Camera , вони заявляють:

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

На сторінці інформації про android.hardware.camera2(зв'язане вище) зазначено:

Пакет android.hardware.camera2 забезпечує інтерфейс до окремих пристроїв камер, підключених до пристрою Android. Він замінює застарілий клас Camera.

Проблема

Перевіривши цю документацію, ви виявите, що реалізація цих 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;
}

Проти 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 представлення старих int cameraID, що, ймовірно, безпечніше.

Один навколо

Тепер, щоб вирішити цю величезну різницю, ви можете спочатку реалізувати інтерфейс і посилатись на цей інтерфейс у своєму коді.

Тут я перерахую код для цього інтерфейсу та 2 реалізації. Ви можете обмежити реалізацію тим, що ви фактично використовуєте API камери, щоб обмежити обсяг роботи.

У наступному розділі я швидко поясню, як завантажити те чи інше.

Інтерфейс, що обгортає все, що вам потрібно, щоб обмежити цей приклад, у мене є лише два способи.

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

Тепер у вас є клас для старих апаратних апаратів камери:

@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;
    }
}

І ще одна для нових апаратних програм:

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
Що робити, якщо мені потрібно підтримувати рівень Android API менше 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 як для поточних пристроїв, так і в майбутнє; Я зіткнувся з тими ж проблемами - і не знайшов сторонньої бібліотеки, яка б’є два API, ймовірно, тому, що вони дуже різні, я звернувся до основних керівників ООП .

2 API помітно відрізняються, що робить їх обмін проблематичним для клієнтських об'єктів, які очікують інтерфейсів, представлених у старому API. Новий API має різні об’єкти з різними методами, побудовані з використанням іншої архітектури. Отримав любов до Google, але безкорисливий! це засмучує.

Тому я створив інтерфейс, орієнтований лише на функціональність камери, яка потрібна моєму додатку, і створив просту обгортку для обох API, яка реалізує цей інтерфейс. Таким чином, моя діяльність з фотоапарата не повинна дбати про те, на якій платформі працює її камера ...

Я також створив Singleton для управління API (ими); інстанціювання обгортки старішого API з моїм інтерфейсом для старих пристроїв з ОС Android та нового класу обгортки API для нових пристроїв, що використовують новий API. Синглтон має типовий код для отримання рівня API, а потім встановлює правильний об'єкт.

Один і той же інтерфейс використовується обома класами обгортки , тому не має значення, чи додаток працює на Jellybean або Marshmallow - доки інтерфейс надає моєму додатку те, що потрібно від 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
чому б не додати коди в коментарях безпосередньо до Відповіді?
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.