2015-06-01 117 views
0

我正在嘗試編寫一款適用於相機的android應用程序。 我在紋理視圖中顯示相機的預覽,這是工作。如果按下按鈕,相機會拍攝一張照片並在屏幕後半部分的圖像視圖中顯示。 但每次我按下按鈕,我的應用程序停止工作,它告訴我的錯誤如何顯示從相機拍攝的圖像

android.view.ViewRootImpl $ CalledFromWrongThreadException:只有創建視圖層次可以觸摸的意見 原來的線程。

所以我查了一下,看起來我無法改變imageview的圖像,因爲我嘗試了。但我不知道如何解決我的問題。你能給我一些建議嗎?這是我的代碼:圖像在方法takePicture()中的「ImageReader.OnImageAvailableListener」中更改。

public class MainActivityOld extends Activity { 

    private TextureView mTextureView; 
    private ImageView mImageView; 
    private CameraDevice mCameraDevice; 
    private Size mPreviewSize; 
    private CaptureRequest.Builder mPreviewBuilder; 
    private CameraCaptureSession mPreviewSession; 

    private Button mBtnShot; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     //no titlebar 
     requestWindowFeature(Window.FEATURE_NO_TITLE); 
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 
     setContentView(R.layout.activity_main); 

     mTextureView = (TextureView) findViewById(R.id.texture); 
     mTextureView.setSurfaceTextureListener(mSurfaceListener); 

     mImageView = (ImageView) findViewById(R.id.lastPicture); 

     mBtnShot = (Button) findViewById(R.id.btn_takepicture); 
     mBtnShot.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       takePicture(); 
      } 
     }); 
    } 

    private void takePicture() { 
     Log.e("MyTag", "Take picture"); 
     CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 

     try { 
      CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId()); 
      Size[] jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG); 
      int width = jpegSizes[0].getWidth(); 
      int height = jpegSizes[0].getHeight(); 

      ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1); 


      List<Surface> outputSurfaces = new ArrayList<Surface>(2); 
      outputSurfaces.add(reader.getSurface()); 
      outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture())); 


      final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 
      captureBuilder.addTarget(reader.getSurface()); 
      captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 

      ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){ 

       @Override 
       public void onImageAvailable(ImageReader reader) { 
        Image image = reader.acquireLatestImage(); 
        ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 
        byte[] bytes = new byte[buffer.capacity()]; 
        buffer.get(bytes); 
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 
        mImageView.setImageBitmap(bitmap); 
       } 
      }; 


      HandlerThread thread = new HandlerThread("CameraPicture"); 
      thread.start(); 
      final Handler backgroundHandler = new Handler(thread.getLooper()); 
      reader.setOnImageAvailableListener(readerListener,backgroundHandler); 

      final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() { 

       @Override 
       public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { 
        super.onCaptureCompleted(session, request, result); 
        startPreview(); 
       } 
      }; 
      mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() { 

       @Override 
       public void onConfigured(CameraCaptureSession session) { 
        try { 
         session.capture(captureBuilder.build(), captureListener, backgroundHandler); 
        } catch (CameraAccessException e) { 
         e.printStackTrace(); 
        } 
       } 

       @Override 
       public void onConfigureFailed(CameraCaptureSession session) { 
       } 
      }, backgroundHandler); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

    private void openCamera() { 
     CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); 
     try { 
      String cameraId = manager.getCameraIdList()[0]; 
      CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); 
      StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 
      mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0]; 

      manager.openCamera(cameraId, mStateCallback, null); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
     Log.e("MyTag", "openCamera"); 
    } 

    private TextureView.SurfaceTextureListener mSurfaceListener = new TextureView.SurfaceTextureListener() { 
     @Override 
     public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { 
      Log.e("myLog", "onSurfaceTextureAvailable, width=" + width + ",height=" + height); 
      openCamera(); 
     } 

     @Override 
     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { 

     } 

     @Override 
     public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { 
      return false; 
     } 

     @Override 
     public void onSurfaceTextureUpdated(SurfaceTexture surface) { 

     } 
    }; 

    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { 

     @Override 
     public void onOpened(CameraDevice camera) { 
      Log.e("myTag", "onOpened"); 
      mCameraDevice = camera; 
      startPreview(); 
     } 

     @Override 
     public void onDisconnected(CameraDevice camera) { 
      Log.e("myTag", "onDisconnected"); 
     } 

     @Override 
     public void onError(CameraDevice camera, int error) { 
      Log.e("myTag", "onDisconnected"); 
     } 
    }; 

    protected void startPreview() { 
     if (mCameraDevice == null || mTextureView.isAvailable() || mPreviewSize == null) { 
      Log.e("MyTag", "startPreview failed, still working, so just ignore it"); 
      // return; 
     } 
     SurfaceTexture texture = mTextureView.getSurfaceTexture(); 
     texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); 
     Surface surface = new Surface(texture); 

     try { 
      mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
     mPreviewBuilder.addTarget(surface); 

     try { 
      mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { 

       @Override 
       public void onConfigured(CameraCaptureSession session) { 
        mPreviewSession = session; 
        updatePreview(); 
       } 

       @Override 
       public void onConfigureFailed(CameraCaptureSession session) { 
        Toast.makeText(MainActivityOld.this, "onConfigureFailed", Toast.LENGTH_LONG).show(); 
       } 
      }, null); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

    protected void updatePreview() { 
     mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); 
     HandlerThread thread = new HandlerThread("CameraPreview"); 
     thread.start(); 
     Handler backgroundHandler = new Handler(thread.getLooper()); 

     try { 
      mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler); 
     } catch (CameraAccessException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

回答

1

我認爲你會更好地嘗試流到表面視圖,不知道這甚至可以用imageview來完成。

試試這個tutorial它應該讓你在正確的方向

this由谷歌

+0

您的鏈接仍然是對舊的API,我嘗試使用'camera2'。因爲我還不習慣安卓系統,你能否再解釋一下你的想法,或者你還有其他有用的,更新的鏈接?謝謝 – Jonas

+0

我已經更新了我的答案希望它可以幫助 – kgpmurray

+0

我現在改變了我的程序,我爲拍攝的圖片定位了第二個'TextureView'。所以我不再需要'ImageReader'。我使用函數'TextureView.getBitmap()'直接從第二個'TextureView'獲取拍攝圖像的位圖。你認爲這是一個好的解決方案嗎? – Jonas

1

提供作爲ExceptionCalledFromWrongThreadException更是最新的例子去,你readerListener正在另一個線程,從哪裏你不能改變你的意見。

你的代碼更改爲:

ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){ 
    @Override 
    public void onImageAvailable(final ImageReader reader) { 
     MainActivityOld.this.runOnUIThread(new Runnable() { 
      @Override 
      public void run() { 
       Image image = reader.acquireLatestImage(); 
       ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 
       byte[] bytes = new byte[buffer.capacity()]; 
       buffer.get(bytes); 
       Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 
       mImageView.setImageBitmap(bitmap); 
      } 
     }); 
    } 
}; 
+0

我嘗試了你的建議,將所有內容都放入Runnable類的'run'方法中。我在之前宣佈了'ImageReader reader' final,但我仍然得到相同的錯誤。 – Jonas

+0

'MainActivityOld.this.runOnUIThread(new Runnable(){'是一個重要的部分,以便代碼在UI線程上運行。您是否如上面的答案中所示使用它? –

+0

Android Studio抱怨,我沒有實現'Runnable'類的'run'方法,所以我使用了你的代碼,但是完全用'run'方法包裝了我的函數。 – Jonas

相關問題