Android Kamera android.hardware.Camera veraltet


97

Wenn android.hardware.Cameraes veraltet ist und Sie die Variable nicht verwenden können Camera, was wäre dann die Alternative dazu?



1
Ich hatte dieses Problem mit einer App und fand dies sehr hilfreich. Wenn Sie Absicht verwenden, sind Sie begrenzt. Also erklärt dieses Tutorial eine Alternative: developer.android.com/guide/topics/media/…
Ronaldo Bahia

Antworten:


102

API-Dokumentation

Laut dem Android-Entwicklerhandbuch für android.hardware.Cameraheißt es:

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

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

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

Das Problem

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

Zum Beispiel die Kameraausrichtung einschalten 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 verarbeiten kann.

Beachten Sie, dass ich in diesem einzelnen Codebeispiel bereits die Tatsache umgehen musste, dass die alte Kamera-API mit intGrundelementen für Kamera-IDs arbeitet, während die neue mit StringObjekten arbeitet. In diesem Beispiel habe ich das schnell behoben, indem ich das int als Index in der neuen API verwendet habe. Wenn die zurückgegebene Kamera nicht immer in derselben Reihenfolge ist, führt dies bereits zu Problemen. Ein alternativer Ansatz besteht darin, mit String-Objekten und der String-Darstellung der alten int cameraIDs zu arbeiten, was wahrscheinlich sicherer ist.

Eins weg herum

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

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

Im nächsten Abschnitt werde ich schnell 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 CameraOldoder Ihre CameraNewKlasse zu laden, müssen Sie die API-Ebene überprüfen, da diese CameraNewnur ab API-Ebene 21 verfügbar ist.

Wenn Sie bereits eine Abhängigkeitsinjektion eingerichtet haben, können Sie dies in Ihrem Modul tun, wenn Sie die CameraSupportImplementierung 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 Dienstprogramm erstellen oder das Factory-Muster verwenden, um das richtige zu erstellen. Wichtig ist, dass die API-Ebene überprüft wird.


25
Was ist, wenn ich eine Android-API-Stufe unter 21 unterstützen muss?
Niveuseverto

1
@Angelius Vielleicht wäre diese Dokumentation hilfreich für developer.android.com/guide/topics/media/camera.html - aber das könnte eine separate Frage sein oder nach Fragen suchen, wie veraltete Variablen verwendet werden müssen.

@ Angelius hier ist einige Informationen @SuppressWarningsin diesem QA stackoverflow.com/questions/7397996/…

5
Ich denke nicht nur daran, @deprecated-Klassen zu verwenden, sondern auch, wie man eine App abwärtskompatibel macht. irgendeine offizielle Hilfe dazu? Ich habe eine Idee dazu: ICamera-Schnittstelle, die mit einem Kameraobjekt versehen ist, das der aktuellen Telefonversion entspricht, aber dies ist ein bisschen unkompliziert und schwer zu warten ...
bis zum

@Angelius, was Sie beschreiben, könnte eine separate Frage sein (prüfen Sie, ob sie zuvor gestellt wurde).

5

Mit dem gleichen Problem konfrontiert, ältere Geräte über die veraltete Kamera-API zu unterstützen und die neue Camera2-API sowohl für aktuelle Geräte als auch für die Zukunft zu benötigen; Ich bin auf dieselben Probleme gestoßen - und habe keine Bibliothek eines Drittanbieters gefunden, die die beiden APIs miteinander verbindet. Wahrscheinlich, weil sie sehr unterschiedlich sind, habe ich mich den grundlegenden OOP-Prinzipien zugewandt .

Die beiden APIs unterscheiden sich deutlich, was das Austauschen für Clientobjekte problematisch macht, die die in der alten API dargestellten Schnittstellen erwarten. Die neue API verfügt über verschiedene Objekte mit unterschiedlichen Methoden, die mit einer anderen Architektur erstellt wurden. Ich habe Liebe für Google, aber Ragnabbit! das ist frustrierend

Daher habe ich eine Benutzeroberfläche erstellt, die sich nur auf die Kamerafunktionalität konzentriert, die meine App benötigt, und einen einfachen Wrapper für beide APIs erstellt, der diese Schnittstelle implementiert. Auf diese Weise muss sich meine Kameraaktivität nicht darum kümmern, auf welcher Plattform sie ausgeführt wird ...

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

Die gleiche Schnittstelle wird von beiden Wrapper-Klassen verwendet . Es spielt also keine Rolle, ob die App auf Jellybean oder Marshmallow ausgeführt wird. Solange die Schnittstelle meiner App mit denselben Methodensignaturen das bietet, was sie von einer der Kamera-APIs benötigt. Die Kamera läuft in der App auf die gleiche Weise für neuere und ältere Versionen von Android.

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.


Zum Beispiel:public interface AllCameraInterface { void open(); boolean setDirection(); Bitmap preview(); Bitmap takePhoto(); void close(); }
Robert Sherman

Beispiel: 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(); } }Dann eine Methode, um es zurückzugeben ...
Robert Sherman

anscheinend sind keine Zeilenumbrüche in Kommentaren erlaubt ;-) aber es funktioniert wirklich.
Robert Sherman

4
Warum nicht die Codes in den Kommentaren direkt in die Antwort einfügen?
Angel Koh

@ RobertSherman Hallo Robert, kannst du mir bitte helfen, diesen kleinen Ausschnitt für das Neue neu zu schreiben camera2? Ich bin wirklich verwirrt ... Ich brauche nur die enableAutofocusMethode, um die Kamera zu öffnen und ihren Fokus einzustellen

0

Jetzt müssen wir android.hardware.camera2 als android.hardware verwenden. Die Kamera ist veraltet, was nur unter API> 23 FlashLight funktioniert

   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

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

Einige Telefone (z. B. Samsung Galaxy S6) befinden sich möglicherweise über dem API-Level 21, unterstützen jedoch möglicherweise nicht die Camera2-API.

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 Hardware-Gerät Camera2 Api unterstützt oder nicht.

Es gibt jedoch noch weitere Probleme, die behoben werden müssen, wenn Sie möchten, dass es für eine ernsthafte Anwendung funktioniert: Die automatische Flash-Option funktioniert 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 zurück Kamera-ID und etc.

Der beste Ansatz ist also, einen Fallback-Mechanismus zu haben, da Camera2 aus irgendeinem Grund nicht gestartet werden kann. Sie können Camera1 ausprobieren. Wenn dies ebenfalls fehlschlägt, können Sie Android anrufen, um die Standardkamera für Sie zu öffnen.


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


 }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.