wake-up-neo.net

Android Kamera Android.hardware.Camera veraltet

wenn Android.hardware.Camera ist veraltet und Sie können die Variable Camera nicht verwenden. Was wäre dann die Alternative dazu?

89
raja121

API-Dokumentation

Laut Android-Entwicklerhandbuch für Android.hardware.Camera heißt es:

Wir empfehlen die Verwendung der neuen Android.hardware.camera2 API für neue Anwendungen.

Auf der Informationsseite über Android.hardware.camera2, (oben verlinkt), heißt es:

Das Android.hardware.camera2-Paket bietet eine Schnittstelle zu einzelnen Kamerageräten, die an ein Android Gerät angeschlossen sind. Es ersetzt die veraltete Kameraklasse.

Das Problem

Wenn Sie diese Dokumentation überprüfen, werden Sie feststellen, dass die Implementierung dieser 2 Kamera-APIs sehr unterschiedlich ist.

Zum Beispiel Kameraausrichtung auf Android.hardware.camera

@Override
public int getOrientation(final int cameraId) {
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(cameraId, info);
    return info.orientation;
}

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

Dies macht es schwierig, von einem zum anderen zu wechseln und Code zu schreiben, der beide Implementierungen unterstützt.

Beachten Sie, dass ich in diesem einzigen Codebeispiel bereits die Tatsache umgehen musste, dass die alte Kamera-API mit int Primitiven für Kamera-IDs arbeitet, während die neue mit String Objekten arbeitet. In diesem Beispiel habe ich das schnell behoben, indem ich int als Index in der neuen API verwendet habe. Wenn die Kamera nicht immer in der gleichen Reihenfolge zurückgegeben wird, treten bereits Probleme auf. Ein alternativer Ansatz besteht darin, mit String-Objekten und der String-Darstellung der alten int cameraIDs zu arbeiten, was wahrscheinlich sicherer ist.

Einer weg herum

Um diesen großen Unterschied zu umgehen, können Sie zunächst eine Schnittstelle implementieren und diese Schnittstelle in Ihrem Code referenzieren.

Hier werde ich Code für diese Schnittstelle und die 2 Implementierungen auflisten. Sie können die Implementierung auf die tatsächliche Verwendung der Kamera-API beschränken, um den Arbeitsaufwand zu begrenzen.

Im nächsten Abschnitt werde ich kurz erklären, wie man das eine oder andere lädt.

Um dieses Beispiel einzuschränken, habe ich hier nur zwei Methoden.

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

Habe jetzt eine Klasse für die alte Kamera Hardware 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;
    }
}

Und noch eine für die neue Hardware-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;
        }
    }
}

Laden der richtigen API

Um nun entweder Ihre Klasse CameraOld oder CameraNew zu laden, müssen Sie die API-Ebene überprüfen, da CameraNew nur ab API-Ebene 21 verfügbar ist.

Wenn Sie die Abhängigkeitsinjektion bereits eingerichtet haben, können Sie dies in Ihrem Modul tun, wenn Sie die Implementierung CameraSupport bereitstellen. Beispiel:

@Module public class CameraModule {

    @Provides
    CameraSupport provideCameraSupport(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop) {
            return new CameraNew(context);
        } else {
            return new CameraOld();
        }
    } 
}

Wenn Sie DI nicht verwenden, können Sie einfach ein Hilfsprogramm erstellen oder mit dem Factory-Muster das richtige erstellen. Ein wichtiger Teil ist, dass die API-Ebene überprüft wird.

95
user4469467

mit dem gleichen Problem konfrontiert Unterstützung älterer Geräte über die veraltete Kamera-API und Benötigen der neuen Kamera2-API sowohl für aktuelle Geräte als auch für zukünftige Geräte; Ich bin auf die gleichen Probleme gestoßen - und habe nicht eine Drittanbieter-Bibliothek gefunden, die die beiden APIs überbrückt, wahrscheinlich, weil sie sehr unterschiedlich sind. Ich habe mich an Basic gewandt OOP Auftraggeber.

Die beiden APIs unterscheiden sich deutlich voneinander, sodass das Austauschen für Clientobjekte problematisch ist, wenn die in der alten API dargestellten Schnittstellen erwartet werden. Die neue API verfügt über unterschiedliche Objekte mit unterschiedlichen Methoden, die unter Verwendung einer unterschiedlichen Architektur erstellt wurden. Ich habe Liebe für Google, aber Ragnabbit! das ist frustrierend.

Also habe ich ein Interface erstellt, das sich nur auf die Kamerafunktionalität konzentriert, die meine App benötigt, und einen einfachen Wrapper für both APIs erstellt, der dieses Interface implementiert. Auf diese Weise funktioniert meine Kameraaktivität nicht muss sich nicht darum kümmern, auf welcher Plattform es läuft ...

Ich habe auch ein Singleton eingerichtet, um die API (s) zu verwalten. Instanziieren des Wrappers der älteren API mit meiner Schnittstelle für ältere Android OS-Geräte und der Wrapper-Klasse der neuen API für neuere Geräte unter Verwendung der neuen API. Der Singleton verfügt über typischen Code zum Abrufen der API-Ebene und anschließend der Instanzen das richtige Objekt.

Dieselbe Schnittstelle wird von beiden Wrapper-Klassen verwendet, es spielt also keine Rolle, ob die App auf Jellybean oder Marshmallow ausgeführt wird - vorausgesetzt, die Schnittstelle versorgt meine App mit dem, was sie von einer der Kameras benötigt API mit denselben Methodensignaturen; Die Kamera läuft in der App für neuere und ältere Versionen von Android auf die gleiche Weise.

Der Singleton kann auch einige verwandte Dinge tun, die nicht an die APIs gebunden sind - wie das Erkennen, dass sich tatsächlich eine Kamera auf dem Gerät befindet, und das Speichern in der Medienbibliothek.

Ich hoffe die Idee hilft dir weiter.

6
Robert Sherman

Jetzt müssen wir Android.hardware.camera2 verwenden, da Android.hardware.Camera veraltet ist. Dies funktioniert nur mit 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;
                    }


            }
        });
    }
}

Die hier angegebenen Antworten, welche Kamera-API verwendet werden soll, sind falsch. Oder besser gesagt, sie sind unzureichend.

Einige Handys (z. B. Samsung Galaxy S6) haben möglicherweise eine höhere API-Stufe als 21, unterstützen jedoch möglicherweise die API Camera2 nicht.

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

Die CameraManager-Klasse in Camera2Api verfügt über eine Methode zum Lesen der Kameraeigenschaften. Sie sollten überprüfen, ob das hardwaremäßige Gerät Camera2 Api unterstützt oder nicht.

Es gibt jedoch noch weitere Probleme, die behoben werden müssen, wenn Sie es wirklich für eine ernsthafte Anwendung verwenden möchten: So funktioniert die Auto-Flash-Option möglicherweise nicht für einige Geräte, oder der Akkuladestand des Telefons führt möglicherweise zu einer RuntimeException auf der Kamera, oder das Telefon gibt möglicherweise eine ungültige Meldung zurück Kamera-ID und usw.

Daher ist es am besten, einen Fallback-Mechanismus zu verwenden, da Camera2 aus irgendeinem Grund nicht gestartet werden kann. Versuchen Sie es mit Camera1. Wenn dies ebenfalls fehlschlägt, können Sie Android) anrufen, um die Standardkamera für Sie zu öffnen.

0
Oguz Ozcan