2016-03-30 23 views
4

Camera API kullanarak resimleri yakalamak için kullanılan özel bir aktiviteye sahip Xamarin'i kullanarak Android için bir uygulama yazıyorum. Bu etkinlik, test ettiğim tüm cihazlarda mükemmel bir şekilde çalışıyor. Ancak, bazı kullanıcılar, resim çekmeye çalışırken uygulamanın tamamen kilitlendiğini bildiriyorlardı. Tüm bu kullanıcıların Samsung telefonlarını kullandıkları ve maalesef test etmek için uygun bir cihazım olmadığı kısa sürede belirgindi.Samsung telefonlarında resim çekilemiyor

Neyse ki özel durum ve yığın izini yakalayabildim, ancak bu soruna neden olabilecekleri konusunda bir kayıp yapıyorum. İstisna, yığın izleme ve sorunlu kod aşağıdadır.

Bu, tam ekran kamera önizleme, flaş değiştirme ve yakalama düğmesi ile oldukça basit bir etkinliktir. Camera API'sini kurmak ve etkileşimde bulunmak için özel bir CameraHelper sınıfını kullanır. Kamera yapılandırılmış ve kullanıcı TakePicture yöntemini etkileşime ve tetikleyebilmeden önce önizleme OnSurfaceTextureAvailable yöntemi tarafından görüntülenir.

İstisna Yığın İzleme

java.lang.RuntimeException: takePicture failed 
android.hardware.Camera.native_takePicture(Native Method):0 
android.hardware.Camera.takePicture(Camera.java:1523):0 
android.hardware.Camera.takePicture(Camera.java:1468):0 
md5efa7d89b8a471e1a97a183b83296df21.CameraHelper.n_onAutoFocus(Native Method):0 
md5efa7d89b8a471e1a97a183b83296df21.CameraHelper.onAutoFocus(CameraHelper.java:39):0 

Yöntemleri CameraHelper

// Implements Camera.IPictureCallback and Camera.IAutoFocusCallback 

public void OnSurfaceTextureAvailable(object sender, TextureView.SurfaceTextureAvailableEventArgs e) 
{ 
    // Get the camera and set its orientation 
    try 
    { 
    _camera = Camera.Open(_cameraInt); 
    } 
    catch (Exception ex) 
    { 
    _callback.OnInitializationFailed(ex); 
    return; 
    } 

    var orientation = GetDisplayOrientation(); 
    _camera.SetDisplayOrientation(orientation); 

    // Set the camera parameters 
    var cameraParameters = _camera.GetParameters(); 

    if (cameraParameters.SupportedFocusModes != null && cameraParameters.SupportedFocusModes.Contains(Camera.Parameters.FocusModeContinuousPicture)) 
    cameraParameters.FocusMode = Camera.Parameters.FocusModeContinuousPicture; 

    if (cameraParameters.SupportedFlashModes != null && cameraParameters.SupportedFlashModes.Contains(Camera.Parameters.FlashModeAuto)) 
    { 
    cameraParameters.FlashMode = Camera.Parameters.FlashModeAuto; 
    HasFlash = true; 
    } 

    cameraParameters.JpegQuality = JPEG_QUALITY; 

    // Set the picture resolution 
    var pictureSize = GetIdealPictureSize(cameraParameters.SupportedPictureSizes, MAX_MEGAPIXELS); 
    _imageWidth = pictureSize.Width; 
    _imageHeight = pictureSize.Height; 
    cameraParameters.SetPictureSize(pictureSize.Width, pictureSize.Height); 

    // Set the preview resolution to best match the TextureView 
    var previewSize = GetIdealPreviewSize(cameraParameters.SupportedPreviewSizes, _previewTexture.Height, _previewTexture.Width); 
    cameraParameters.SetPreviewSize(previewSize.Width, previewSize.Height); 

    // Begin outputting camera preview 
    _camera.SetParameters(cameraParameters); 
    _camera.SetPreviewTexture(_previewTexture.SurfaceTexture); 
    _camera.StartPreview(); 
    UpdatePreviewTextureMatrix(); // Ensure the preview is displayed without warping 

    // Wait for the preview 
    EventHandler<TextureView.SurfaceTextureUpdatedEventArgs> h = null; 
    _previewTexture.SurfaceTextureUpdated += h = (s, e2) => 
    { 
    _previewTexture.SurfaceTextureUpdated -= h; 
    _callback.OnCameraPreviewReady(); 
    _ready = true; 
    }; 
} 

public void TakePicture() 
{ 
    if (!_ready || _busy) 
    { 
    var e = new Exception("Camera not ready"); 
    OnTakePictureFailed(e); 
    return; 
    } 

    _busy = true; 

    _camera.AutoFocus(this); 
} 

public void OnAutoFocus(bool success, Camera camera) 
{ 
    try 
    { 
    _camera.TakePicture(null, null, this); 
    } 
    catch (Exception e) 
    { 
    // On Samsung phones the exception is always thrown here 
    OnTakePictureFailed(e); 
    } 
} 

public void OnPictureTaken(byte[] data, Camera camera) 
{ 
    _busy = false; 
    var rotation = GetPictureRotation(); 
    _callback.OnPictureTaken(data, rotation, _imageWidth, _imageHeight); 
} 

private void OnTakePictureFailed(Exception e) 
{ 
    _busy = false; 
    _callback.OnTakePictureFailed(e); 
} 

kamera mevcuttur ve önizleme sorunu olmadan gösteriliyor ve istisna sadece Samsung cihazlarında atılır.

+0

O 'startPreview()' yöntem değil gibi görünüyor Resmi çekmeden önce çağrılıyor. Fotoğraf çektikten sonra tekrar aramak isteyebilirsiniz. Bu 'Kamera' sınıfı için en iyi 8 adımı gözden geçirin: http://developer.android.com/reference/android/hardware/Camera.html –

+0

Merhaba Jon, önizleme başlatıldı. Bunu, yukarda yayınladığım kodda görebilirsiniz. –

cevap

2

Samsung Galaxy telefonun ilk kez otomatik odaklanmadığı durumlarda istisna atıldı - çoğu cihaz yalnızca bir kez odaklanmaya çalışacak, Samsung Galaxy telefonları üç kez yeniden denemeye çalışacak ve her denemeden sonra OnAutoFocus geri aramayı arayacak . Geri aramada kodum Camera.TakePicture olarak adlandırıldığı için, hızlı bir şekilde art arda iki veya daha fazla çağrılabilir, dolayısıyla bir resim çekilirken fotoğraf çekmeye çalışır ve istisnayı atar.

çözüm otomatik odaklanma geri arama zaten olmuş olsun izlenen bir boolean eklemek basitçe, ve eğer öyleyse, Camera.TakePicture arayarak atlamak:

public void OnAutoFocus(bool success, Camera camera) 
{ 
    if (_hasAttemptedFocus) return; 
    else _hasAttemptedFocus = true; 

    _camera.TakePicture(null, null, this); 
} 

public void OnPictureTaken(byte[] data, Camera camera) 
{ 
    _busy = _hasAttemptedFocus = false; 

    // Do something with the image 
} 
+0

, 'OnOutoFocus()' işlevine yapılan tüm aramalarda '' '' true' döndürüyor? – allgood

+0

Geç cevap için özür dileriz, ancak başka birinin ilgilenmesi durumunda: kamera başarılı bir şekilde odaklanırsa ya da yanlış yazıyorsa, doğru döner. Otomatik netlemenin başarısız olması durumunda TakePicture'a yapılan çağrıyı atlamak mümkün olabilir, ancak belirli bir donanımın kaç kez denemeyeceğini bilmeden, kullanıcının deklanşöre basma riskini ve hiçbir zaman çekilmediğinden emin olabilirsiniz. Bu, ya bulanık bir resim çeker (kodumda olduğu gibi) ya da sadece autofocus ilk kez başarısız olduğunda bir hata görüntülemenizi ve sonraki çağrıları {{OnAutoFocus}} göz ardı etmenizi tavsiye eder. –

İlgili konular