2016-05-29 84 views
2

我正在嘗試使用設備Camera和Mobile Vision API掃描QR碼。爲此,我創建了一個SurfaceView並將圖像流提取到SurfaceView,並啓用BarcodeDetector,然後按需要的方法讀取檢測到的QR碼。下面是代碼的活動:使用相機掃描QR代碼崩潰應用程序|可能的修復?

QrScanActivity.class

public class QrScanActivity extends AppCompatActivity 
{ 
    private SurfaceView cameraView; 
    private TextView barcodeInfo; 
    private BarcodeDetector barcodeDetector; 
    private CameraSource cameraSource; 
    private static final String TAG = "QR_ACTIVITY"; 
    private static final int REQUEST_CAMERA = 0; 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_qr_scan); 

     cameraView = (SurfaceView) findViewById(R.id.camera_view); 
     barcodeInfo = (TextView) findViewById(R.id.code_info); 

     barcodeDetector = 
       new BarcodeDetector.Builder(this) 
         .setBarcodeFormats(Barcode.QR_CODE) 
         .build(); 

     cameraSource = new CameraSource 
       .Builder(this, barcodeDetector) 
       .setRequestedPreviewSize(640, 480) 
       .build(); 

     cameraView.getHolder().addCallback(new SurfaceHolder.Callback() { 
      @Override 
      public void surfaceCreated(SurfaceHolder holder) { 
       if (ActivityCompat.checkSelfPermission(QrScanActivity.this, Manifest.permission.CAMERA) 
         != PackageManager.PERMISSION_GRANTED) { 
        requestCameraPermission(); 

       } 
       try { 
        cameraSource.start(cameraView.getHolder()); 
       } catch (IOException ie) { 
        Log.e("CAMERA SOURCE", ie.getMessage()); 
       } 
      } 

      @Override 
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
      } 

      @Override 
      public void surfaceDestroyed(SurfaceHolder holder) { 
       cameraSource.stop(); 
      } 
     }); 

     barcodeDetector.setProcessor(new Detector.Processor<Barcode>() { 
      @Override 
      public void release() { 
      } 

      @Override 
      public void receiveDetections(Detector.Detections<Barcode> detections) { 
       final SparseArray<Barcode> barcodes = detections.getDetectedItems(); 

       if (barcodes.size() != 0) { 
        barcodeInfo.post(new Runnable() { // Use the post method of the TextView 
         public void run() { 
          barcodeInfo.setText( // Update the TextView 
            barcodes.valueAt(0).displayValue 
          ); 
         } 
        }); 
       } 
      } 
     }); 
    } 

     private void requestCameraPermission() { 
     Log.i("CAM","CAMERA permission has NOT been granted. Requesting permission."); 

     // BEGIN_INCLUDE(camera_permission_request) 
     if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)) 
     { 

      Snackbar.make(findViewById(android.R.id.content), R.string.permission_camera_rationale, 
        Snackbar.LENGTH_INDEFINITE) 
        .setAction(R.string.ok, new View.OnClickListener() { 
         @Override 
         public void onClick(View view) { 
          ActivityCompat.requestPermissions(QrScanActivity.this, 
            new String[]{Manifest.permission.CAMERA}, 
            REQUEST_CAMERA); 
         } 
        }) 
        .show(); 
     } else { 


      ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 
        REQUEST_CAMERA); 
     } 
     // END_INCLUDE(camera_permission_request) 
    } 


    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 
              @NonNull int[] grantResults) { 

     if (requestCode == REQUEST_CAMERA) 
     { 

      Log.i(TAG, "Received response for Camera permission request."); 
      if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
        Log.i(TAG, "CAMERA permission has now been granted. Showing preview."); 
       Snackbar.make(findViewById(android.R.id.content), R.string.permision_available_camera, 
         Snackbar.LENGTH_SHORT).show(); 
      } else { 
       Log.i(TAG, "CAMERA permission was NOT granted."); 
       Snackbar.make(findViewById(android.R.id.content), R.string.permissions_not_granted, 
         Snackbar.LENGTH_SHORT).show(); 

      } 


     } 
     else { 
      super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
     } 
    } 




} 

activity_qr_scan.xml

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/activity_qr_scan" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent"> 

    <SurfaceView 
     android:layout_width="400dp" 
     android:layout_height="280dp" 
     android:layout_marginTop="30dp" 
     android:id="@+id/camera_view" 
     /> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:id="@+id/code_info" 
     android:layout_below="@+id/camera_view" 
     android:textSize="20sp" 
     android:layout_marginTop="30dp" 
     android:layout_centerHorizontal="true" 
     android:text="Nothing to read." 

     /> 


</RelativeLayout> 

,當應用程序運行中得到的logcat的:

Logcat

E/AndroidRuntime:致命異常:主 工藝:com.shreybank.shrey,PID:12044 了java.lang.RuntimeException:失敗在android.hardware.Camera(相機連接到相機服務 。 java:518) at com.google.android.gms.vision.CameraSource.zzBZ(Unknown Source)android.hardware.Camera.open .CameraSource.start(Unknown Source) at com.shreybank.shrey.activities.QrScanActivity $ 1.surfaceCreated(QrScanActivity.java:64) at android.view.SurfaceView.updateWindow(SurfaceView.java:583) 在android.view.SurfaceView $ 3.onPreDraw(SurfaceView.java:177) 在android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:944) 在android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2055) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107) at android.view.ViewRootImpl $ TraversalRunnable.run(ViewRootImpl.java:6013) at android.view.Choreographer $ CallbackRecord.run(Choreographer.java:858 ) at android.view.Choreographer.doCallbacks(Choreographer.java:670) at android.view.Choreographer.doFrame(Choreographer.java:606) at android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.java:844) ) at android.os.Handler.handleCallback(Handler.java:739) 在android.os.Handler.dispatchMessage(Handler.java:95) 在android.os.Looper.loop(Looper.java:148) 在機器人。 (在本地方法) at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:726) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

+0

它說它無法打開相機。看着你的代碼,我看到你正在請求相機許可,並且在你開始相機預覽之後,這是不正確的。在授予權限時您應該只打開相機。 –

+0

我是新來的運行時權限系統!我應該如何更改代碼,以便只有在授予許可時纔打開相機? – OBX

+0

查看下面的答案,它顯示了您在授予許可後如何啓動相機。 –

回答

0

您必須設置運行時權限來克服此問題。在開始QrScanActivity之前,你已經打過電話了。

if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { 
     ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, REQUEST_READ_CAMERA); 
    } 
    else { 
     // Already grant Camera permission. Now call your QR scan Activity 
    } 
}else { 
    // call your QR scan Activity 
} 

當用戶授予您可以打開QrScanActivity onRequestPermissionsResult方法的權限。

@Override 
public void onRequestPermissionsResult(int requestCode, 
             String permissions[], int[] grantResults) { 
    switch (requestCode) { 
     case REQUEST_READ_CAMERA: { 
      if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
       // permission has granted . Call the QR scan Activity 
      } else { 
       // permission denied 
      } 
      return; 
     } 
    } 
} 
+0

運行時權限請求也在QrScanActivity活動中進行管理。在啓動活動之前不需要檢查權限。 – USKMobility

0

更新您的QrScanActivity,移動相機拍攝源創建代碼initCameraSource方法,檢查權限CAMERA,如果授予通話initCameraSource方法,否則申請許可。授予權限後,從onRequestPermissionsResult調用initCameraSource。

public class QrScanActivity extends AppCompatActivity 
{ 
    private SurfaceView cameraView; 
    private TextView barcodeInfo; 
    private BarcodeDetector barcodeDetector; 
    private CameraSource cameraSource; 
    private static final String TAG = "QR_ACTIVITY"; 
    private static final int REQUEST_CAMERA = 0; 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_qr_scan); 
     int permissionCheck = ContextCompat.checkSelfPermission(this, 
       Manifest.permission.CAMERA); 
     if(permissionCheck == PackageManager.PERMISSION_GRANTED) 
      initCameraSource 
     else 
      requestCameraPermission(); 

    } 

     private void requestCameraPermission() { 
     Log.i("CAM","CAMERA permission has NOT been granted. Requesting permission."); 

     // BEGIN_INCLUDE(camera_permission_request) 
     if (ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)) 
     { 

      Snackbar.make(findViewById(android.R.id.content), R.string.permission_camera_rationale, 
        Snackbar.LENGTH_INDEFINITE) 
        .setAction(R.string.ok, new View.OnClickListener() { 
         @Override 
         public void onClick(View view) { 
          ActivityCompat.requestPermissions(QrScanActivity.this, 
            new String[]{Manifest.permission.CAMERA}, 
            REQUEST_CAMERA); 
         } 
        }) 
        .show(); 
     } else { 


      ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 
        REQUEST_CAMERA); 
     } 
     // END_INCLUDE(camera_permission_request) 
    } 


    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, 
              @NonNull int[] grantResults) { 

     if (requestCode == REQUEST_CAMERA) 
     { 

      Log.i(TAG, "Received response for Camera permission request."); 
      if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 
        Log.i(TAG, "CAMERA permission has now been granted. Showing preview."); 
        initCameraSource(); 
      } else { 
       Log.i(TAG, "CAMERA permission was NOT granted."); 
       Snackbar.make(findViewById(android.R.id.content), R.string.permissions_not_granted, 
         Snackbar.LENGTH_SHORT).show(); 

      } 


     } 
     else { 
      super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
     } 
    } 


    private void initCameraSource(){ 
     cameraView = (SurfaceView) findViewById(R.id.camera_view); 
     barcodeInfo = (TextView) findViewById(R.id.code_info); 

     barcodeDetector = 
       new BarcodeDetector.Builder(this) 
         .setBarcodeFormats(Barcode.QR_CODE) 
         .build(); 

     cameraSource = new CameraSource 
       .Builder(this, barcodeDetector) 
       .setRequestedPreviewSize(640, 480) 
       .build(); 

     cameraView.getHolder().addCallback(new SurfaceHolder.Callback() { 
      @Override 
      public void surfaceCreated(SurfaceHolder holder) { 
       if (ActivityCompat.checkSelfPermission(QrScanActivity.this, Manifest.permission.CAMERA) 
         != PackageManager.PERMISSION_GRANTED) { 
        requestCameraPermission(); 

       } 
       try { 
        cameraSource.start(cameraView.getHolder()); 
       } catch (IOException ie) { 
        Log.e("CAMERA SOURCE", ie.getMessage()); 
       } 
      } 

      @Override 
      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
      } 

      @Override 
      public void surfaceDestroyed(SurfaceHolder holder) { 
       cameraSource.stop(); 
      } 
     }); 

     barcodeDetector.setProcessor(new Detector.Processor<Barcode>() { 
      @Override 
      public void release() { 
      } 

      @Override 
      public void receiveDetections(Detector.Detections<Barcode> detections) { 
       final SparseArray<Barcode> barcodes = detections.getDetectedItems(); 

       if (barcodes.size() != 0) { 
        barcodeInfo.post(new Runnable() { // Use the post method of the TextView 
         public void run() { 
          barcodeInfo.setText( // Update the TextView 
            barcodes.valueAt(0).displayValue 
          ); 
         } 
        }); 
       } 
      } 
     }); 
    } 


}