Wenn android.hardware.Camera
es veraltet ist und Sie die Variable nicht verwenden können Camera
, was wäre dann die Alternative dazu?
Wenn android.hardware.Camera
es veraltet ist und Sie die Variable nicht verwenden können Camera
, was wäre dann die Alternative dazu?
Antworten:
Laut dem Android-Entwicklerhandbuch für android.hardware.Camera
heiß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.
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 int
Grundelementen für Kamera-IDs arbeitet, während die neue mit String
Objekten 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.
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;
}
}
}
Um nun entweder Ihre CameraOld
oder Ihre CameraNew
Klasse zu laden, müssen Sie die API-Ebene überprüfen, da diese CameraNew
nur 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 CameraSupport
Implementierung 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.
@SuppressWarnings
in diesem QA stackoverflow.com/questions/7397996/…
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.
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(); } }
Dann eine Methode, um es zurückzugeben ...
camera2
? Ich bin wirklich verwirrt ... Ich brauche nur die enableAutofocus
Methode, um die Kamera zu öffnen und ihren Fokus einzustellen
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;
}
}
});
}
}
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.
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();
}
}
android.hardware.camera2