In dieser Lektion wird erläutert, wie du die Kamerahardware direkt über die Framework-APIs steuerst.
Hinweis: Diese Seite bezieht sich auf die verworfene Klasse Camera. Wir empfehlen die Verwendung von CameraX oder für bestimmte Anwendungsfälle Camera2. Sowohl CameraX als auch Camera2 unterstützen Android 5.0 (API-Level 21) und höher.
Informationen zur Migration von Camera1 zu CameraX finden Sie unter Camera1 zu CameraX migrieren.
Alternativ können Sie den agentischen Skill für die Migration von Camera1 zu CameraX verwenden.
Die direkte Steuerung einer Gerätekamera erfordert viel mehr Code als das Anfordern von Bildern oder Videos von vorhandenen Kameraanwendungen. Wenn Sie jedoch eine spezielle Kamera-App oder etwas vollständig in die App-UI Integriertes entwickeln möchten, erfahren Sie in dieser Lektion, wie das geht.
Weitere Informationen finden Sie hier:
Kameraobjekt öffnen
Der erste Schritt zur direkten Steuerung der Kamera besteht darin, eine Instanz des Camera-Objekts abzurufen. Wie bei der Android-eigenen Kamera-App wird empfohlen, Camera in einem separaten Thread zu öffnen, der von onCreate() gestartet wird. Dieser Ansatz ist sinnvoll, da der Vorgang einige Zeit dauern und den UI-Thread blockieren kann. In einer einfacheren Implementierung kann das Öffnen der Kamera auf die Methode onResume() verschoben werden, um die Wiederverwendung von Code zu erleichtern und den Kontrollfluss einfach zu halten.
Wenn die Kamera bereits von einer anderen Anwendung verwendet wird, wird beim Aufrufen von Camera.open() eine Ausnahme ausgelöst. Daher wird der Aufruf in einen try-Block eingeschlossen.
Kotlin
private fun safeCameraOpen(id: Int): Boolean { return try { releaseCameraAndPreview() mCamera = Camera.open(id) true } catch (e: Exception) { Log.e(getString(R.string.app_name), "failed to open Camera") e.printStackTrace() false } } private fun releaseCameraAndPreview() { preview?.setCamera(null) mCamera?.also { camera -> camera.release() mCamera = null } }
Java
private boolean safeCameraOpen(int id) { boolean qOpened = false; try { releaseCameraAndPreview(); camera = Camera.open(id); qOpened = (camera != null); } catch (Exception e) { Log.e(getString(R.string.app_name), "failed to open Camera"); e.printStackTrace(); } return qOpened; } private void releaseCameraAndPreview() { preview.setCamera(null); if (camera != null) { camera.release(); camera = null; } }
Seit API-Level 9 unterstützt das Kamera-Framework mehrere Kameras. Wenn Sie die Legacy-API verwenden und open() ohne Argument aufrufen, erhalten Sie die erste rückwärtsgerichtete Kamera.
Kameravorschau erstellen
Wenn Nutzer ein Foto aufnehmen, müssen sie in der Regel eine Vorschau des Motivs sehen, bevor sie den Auslöser drücken. Dazu können Sie eine SurfaceView verwenden, um eine Vorschau dessen zu zeichnen, was der Kamerasensor erfasst.
Kurs ansehen
Wenn Sie eine Vorschau anzeigen möchten, benötigen Sie die Vorschauklasse. Für die Vorschau ist eine Implementierung der android.view.SurfaceHolder.Callback-Schnittstelle erforderlich, über die Bilddaten von der Kamerahardware an die Anwendung übergeben werden.
Kotlin
class Preview( context: Context, val surfaceView: SurfaceView = SurfaceView(context) ) : ViewGroup(context), SurfaceHolder.Callback { var mHolder: SurfaceHolder = surfaceView.holder.apply { addCallback(this@Preview) setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) } ... }
Java
class Preview extends ViewGroup implements SurfaceHolder.Callback { SurfaceView surfaceView; SurfaceHolder holder; Preview(Context context) { super(context); surfaceView = new SurfaceView(context); addView(surfaceView); // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. holder = surfaceView.getHolder(); holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } ... }
Die Vorschauklasse muss an das Camera-Objekt übergeben werden, bevor die Live-Bildvorschau gestartet werden kann, wie im nächsten Abschnitt gezeigt.
Vorschau einrichten und starten
Eine Kamerainstanz und die zugehörige Vorschau müssen in einer bestimmten Reihenfolge erstellt werden, wobei das Kameraobjekt zuerst erstellt werden muss. Im folgenden Snippet wird die Initialisierung der Kamera gekapselt, sodass Camera.startPreview() von der Methode setCamera() aufgerufen wird, wenn der Nutzer die Kamera ändert. Die Vorschau muss auch in der Callback-Methode surfaceChanged() der Vorschauklasse neu gestartet werden.
Kotlin
fun setCamera(camera: Camera?) { if (mCamera == camera) { return } stopPreviewAndFreeCamera() mCamera = camera mCamera?.apply { mSupportedPreviewSizes = parameters.supportedPreviewSizes requestLayout() try { setPreviewDisplay(holder) } catch (e: IOException) { e.printStackTrace() } // Important: Call startPreview() to start updating the preview // surface. Preview must be started before you can take a picture. startPreview() } }
Java
public void setCamera(Camera camera) { if (mCamera == camera) { return; } stopPreviewAndFreeCamera(); mCamera = camera; if (mCamera != null) { List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes(); supportedPreviewSizes = localSizes; requestLayout(); try { mCamera.setPreviewDisplay(holder); } catch (IOException e) { e.printStackTrace(); } // Important: Call startPreview() to start updating the preview // surface. Preview must be started before you can take a picture. mCamera.startPreview(); } }
Kameraeinstellungen ändern
Mit den Kameraeinstellungen kannst du die Art und Weise ändern, wie die Kamera Bilder aufnimmt – von der Zoomstufe bis zur Belichtungskorrektur. In diesem Beispiel wird nur die Vorschaugröße geändert. Weitere Informationen finden Sie im Quellcode der Kamera-App.
Kotlin
override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) { mCamera?.apply { // Now that the size is known, set up the camera parameters and begin // the preview. parameters?.also { params -> params.setPreviewSize(previewSize.width, previewSize.height) requestLayout() parameters = params } // Important: Call startPreview() to start updating the preview surface. // Preview must be started before you can take a picture. startPreview() } }
Java
@Override public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // Now that the size is known, set up the camera parameters and begin // the preview. Camera.Parameters parameters = mCamera.getParameters(); parameters.setPreviewSize(previewSize.width, previewSize.height); requestLayout(); mCamera.setParameters(parameters); // Important: Call startPreview() to start updating the preview surface. // Preview must be started before you can take a picture. mCamera.startPreview(); }
Vorschauausrichtung festlegen
Die meisten Kamera-Apps sperren das Display im Querformat, da dies die natürliche Ausrichtung des Kamerasensors ist. Diese Einstellung verhindert nicht, dass Sie Fotos im Hochformat aufnehmen, da die Ausrichtung des Geräts im EXIF-Header aufgezeichnet wird. Mit der Methode setCameraDisplayOrientation() kannst du die Anzeige der Vorschau ändern, ohne dass sich dies auf die Aufnahme des Bildes auswirkt. In Android-Versionen vor API-Level 14 müssen Sie die Vorschau jedoch beenden, bevor Sie die Ausrichtung ändern, und sie dann neu starten.
Foto aufnehmen
Verwenden Sie die Methode Camera.takePicture(), um ein Bild aufzunehmen, sobald die Vorschau gestartet wurde. Sie können Camera.PictureCallback- und Camera.ShutterCallback-Objekte erstellen und an Camera.takePicture() übergeben.
Wenn Sie kontinuierlich Bilder abrufen möchten, können Sie einen Camera.PreviewCallback erstellen, der onPreviewFrame() implementiert. Für etwas dazwischen können Sie nur ausgewählte Vorschauframes erfassen oder eine verzögerte Aktion einrichten, um takePicture() aufzurufen.
Vorschau neu starten
Nachdem ein Bild aufgenommen wurde, musst du die Vorschau neu starten, bevor der Nutzer ein weiteres Bild aufnehmen kann. In diesem Beispiel wird der Neustart durch Überladen des Auslösers durchgeführt.
Kotlin
fun onClick(v: View) { previewState = if (previewState == K_STATE_FROZEN) { camera?.startPreview() K_STATE_PREVIEW } else { camera?.takePicture(null, rawCallback, null) K_STATE_BUSY } shutterBtnConfig() }
Java
@Override public void onClick(View v) { switch(previewState) { case K_STATE_FROZEN: camera.startPreview(); previewState = K_STATE_PREVIEW; break; default: camera.takePicture( null, rawCallback, null); previewState = K_STATE_BUSY; } // switch shutterBtnConfig(); }
Vorschau beenden und Kamera freigeben
Wenn die Anwendung die Kamera nicht mehr benötigt, ist es Zeit, aufzuräumen. Insbesondere müssen Sie das Camera-Objekt freigeben, da sonst andere Anwendungen, einschließlich neuer Instanzen Ihrer eigenen Anwendung, abstürzen können.
Wann sollten Sie die Vorschau beenden und die Kamera freigeben? Wenn die Vorschauoberfläche zerstört wird, ist das ein ziemlich guter Hinweis darauf, dass es an der Zeit ist, die Vorschau zu beenden und die Kamera freizugeben, wie in diesen Methoden der Klasse Preview gezeigt.
Kotlin
override fun surfaceDestroyed(holder: SurfaceHolder) { // Surface will be destroyed when we return, so stop the preview. // Call stopPreview() to stop updating the preview surface. mCamera?.stopPreview() } /** * When this function returns, mCamera will be null. */ private fun stopPreviewAndFreeCamera() { mCamera?.apply { // Call stopPreview() to stop updating the preview surface. stopPreview() // Important: Call release() to release the camera for use by other // applications. Applications should release the camera immediately // during onPause() and re-open() it during onResume()). release() mCamera = null } }
Java
@Override public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return, so stop the preview. if (mCamera != null) { // Call stopPreview() to stop updating the preview surface. mCamera.stopPreview(); } } /** * When this function returns, mCamera will be null. */ private void stopPreviewAndFreeCamera() { if (mCamera != null) { // Call stopPreview() to stop updating the preview surface. mCamera.stopPreview(); // Important: Call release() to release the camera for use by other // applications. Applications should release the camera immediately // during onPause() and re-open() it during onResume()). mCamera.release(); mCamera = null; } }
Dieses Verfahren war auch Teil der Methode setCamera(). Die Initialisierung einer Kamera beginnt also immer mit dem Beenden der Vorschau.