Bu derste, kamera donanımını doğrudan çerçeve API'lerini kullanarak nasıl kontrol edeceğinizi ele alacağız.
Not: Bu sayfada, desteği sonlandırılan Camera sınıfı ele alınmaktadır. CameraX veya belirli kullanım alanları için Camera2 kullanmanızı öneririz. Hem CameraX hem de Camera2, Android 5.0 (API düzeyi 21) ve sonraki sürümleri destekler.
Bir cihaz kamerasını doğrudan kontrol etmek, mevcut kamera uygulamalarından fotoğraf veya video istemekten çok daha fazla kod gerektirir. Ancak özel bir kamera uygulaması veya uygulama kullanıcı arayüzünüze tamamen entegre edilmiş bir şey oluşturmak istiyorsanız bu derste nasıl yapılacağı gösterilmektedir.
Aşağıdaki ilgili kaynaklara göz atın:
Kamera nesnesini açma
Kamerayı doğrudan kontrol etme işleminin ilk adımı, Camera
nesnesinin bir örneğini elde etmektir. Android'in kendi kamera uygulamasında olduğu gibi, kameraya erişmenin önerilen yolu onCreate()
'ten başlatılan ayrı bir iş parçacığında Camera
'ü açmaktır. Bu yaklaşım, biraz zaman alabileceği ve kullanıcı arayüzü iş parçacığının tıkanmasına neden olabileceği için iyi bir fikirdir. Daha basit bir uygulamada, kameranın açılması onResume()
yöntemine ertelenebilir. Böylece kod yeniden kullanılabilir ve kontrol akışı basit tutulabilir.
Kamera başka bir uygulama tarafından kullanılıyorsa Camera.open()
çağrısı bir istisna oluşturur. Bu nedenle, çağrıyı bir try
bloğuna sarmalıyoruz.
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; } }
Kamera çerçevesi, API düzeyi 9'dan beri birden fazla kamerayı destekler. Eski API'yi kullanıyorsanız ve open()
işlevini bağımsız değişken olmadan çağırırsanız ilk arka kamerayı alırsınız.
Kamera önizlemesini oluşturma
Fotoğraf çekmek için kullanıcıların genellikle deklanşörü tıklamadan önce fotoğrafını çekecekleri nesnenin önizlemesini görmeleri gerekir. Bunu yapmak için kamera sensörünün algıladığı görüntülerin önizlemelerini çizmek üzere SurfaceView
simgesini kullanabilirsiniz.
Önizleme Sınıfı
Önizleme göstermeye başlamak için önizleme sınıfına ihtiyacınız vardır. Önizleme için, kamera donanımından uygulamaya resim verilerini aktarmak için kullanılan android.view.SurfaceHolder.Callback
arayüzünün uygulanması gerekir.
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); } ... }
Canlı resim önizlemesi başlatılmadan önce, önizleme sınıfı sonraki bölümde gösterildiği gibi Camera
nesnesine aktarılmalıdır.
Önizlemeyi ayarlama ve başlatma
Kamera örneği ve ilgili önizlemesi, kamera nesnesi önce olacak şekilde belirli bir sırada oluşturulmalıdır. Aşağıdaki snippet'te, kamerayı başlatma işlemi, kullanıcı kamerayı değiştirmek için bir işlem yaptığında Camera.startPreview()
yöntemi tarafından setCamera()
çağrılacak şekilde kapsüllenir. Önizleme, önizleme sınıfı surfaceChanged()
geri çağırma yönteminde de yeniden başlatılmalıdır.
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(); } }
Kamera ayarlarını değiştirme
Kamera ayarları, yakınlaştırma seviyesinden pozlama telafisine kadar kameranın fotoğraf çekme şeklini değiştirir. Bu örnekte yalnızca önizleme boyutu değiştirilmektedir. Daha fazla örnek için Kamera uygulamasının kaynak koduna bakın.
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(); }
Önizleme yönünü ayarlama
Çoğu kamera uygulaması, kamera sensörünün doğal yönü yatay olduğu için ekranı yatay moda kilitler. Cihazın yönü EXIF başlığına kaydedildiği için bu ayar, dikey modda fotoğraf çekmenizi engellemez. setCameraDisplayOrientation()
yöntemi, resmin nasıl kaydedildiğini etkilemeden önizlemenin nasıl gösterileceğini değiştirmenize olanak tanır. Ancak API düzeyi 14'ten önceki Android sürümlerinde, yönü değiştirmeden önce önizlemenizi durdurup yeniden başlatmanız gerekir.
Fotoğraf çekme
Önizleme başladıktan sonra fotoğraf çekmek için Camera.takePicture()
yöntemini kullanın. Camera.PictureCallback
ve Camera.ShutterCallback
nesneleri oluşturup bunları Camera.takePicture()
'ye iletebilirsiniz.
Resimleri sürekli olarak almak istiyorsanız onPreviewFrame()
uygulayan bir Camera.PreviewCallback
oluşturabilirsiniz. Bu iki seçenek arasında bir şey için yalnızca seçili önizleme karelerini yakalayabilir veya takePicture()
işlevini çağıracak gecikmeli bir işlem ayarlayabilirsiniz.
Önizlemeyi yeniden başlatma
Bir fotoğraf çekildikten sonra kullanıcının başka bir fotoğraf çekmesi için önizlemeyi yeniden başlatmanız gerekir. Bu örnekte, yeniden başlatma işlemi deklanşör düğmesine aşırı yük uygulanarak yapılır.
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(); }
Önizlemeyi durdurma ve kamerayı bırakma
Uygulamanız kamerayı kullanmayı tamamladığında temizleme işlemini yapmanız gerekir. Özellikle Camera
nesnesini serbest bırakmanız gerekir. Aksi takdirde, kendi uygulamanızın yeni örnekleri de dahil olmak üzere diğer uygulamaların kilitlenmesi riskine girersiniz.
Önizlemeyi ne zaman durdurmalı ve kamerayı ne zaman bırakmalısınız? Önizleme yüzeyinizin yok edilmesi, önizlemeyi durdurup kamerayı serbest bırakma zamanının geldiğinin oldukça iyi bir göstergesidir. Preview
sınıfındaki bu yöntemlerde gösterildiği gibi.
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; } }
Dersin önceki bölümlerinde bu prosedür setCamera()
yönteminin bir parçasıydı. Bu nedenle, kamerayı başlatmak her zaman önizlemeyi durdurmakla başlar.