2016-09-22 31 views
7

Buduję aplikację ze skanerem qr za pomocą api google google vision. Mam problem z zatrzymaniem aparatu po odczytaniu kodu qr. przepływ jest MainActivity -> QrActivity , gdy kod qr otrzymał wykrycie, aplikacja powinna powrócić do głównej aktywności.Android cameraSource.stop() powodująca zamrożenie aplikacji

Jeśli nie zadzwonię pod numer cameraSource.release(), działa dobrze, ale urządzenie bardzo się nagrzewa i ma znaczny wpływ na wyczerpanie baterii. jednak jeśli zwolnię źródło kamery, funkcja mainActivity przestaje reagować, a aplikacja ulegnie awarii.

Dlaczego przestaje reagować? i gdzie jest właściwe miejsce na zwolnienie źródła kamery?

QrActivity

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_qr); 
    cancelBtn = (Button) findViewById(R.id.cancel_button); 
    cancelBtn.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      onBackPressed(); 
     } 
    }); 

    new QrReader(this); 
} 

QrReader Klasa

public class QrReader { 

    private static final String TAG = "QrReader"; 

    private SurfaceView cameraView; 
    private TextView barcodeInfo; 
    private BarcodeDetector barcodeDetector; 
    private CameraSource cameraSource; 
    private Activity mActivity; 
    private AccessPointCredentials barCodeData; 

    public QrReader(Activity activity) { 
     this.mActivity = activity; 

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

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

     cameraSource = new CameraSource 
       .Builder(mActivity, barcodeDetector) 
       .setAutoFocusEnabled(true) 
       .build(); 

     cameraView.getHolder().addCallback(new SurfaceHolder.Callback() { 

      @Override 
      public void surfaceCreated(SurfaceHolder holder) { 

       cameraSource = new CameraSource 
         .Builder(mActivity, barcodeDetector) 
         .setAutoFocusEnabled(true) 
         .setFacing(0) 
         .build(); 
       try {     
        cameraSource.start(cameraView.getHolder()); 

       } catch (Exception ioe) { 
        ioe.printStackTrace(); 
       } 
      } 

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

      @Override 
      public void surfaceDestroyed(SurfaceHolder holder) { 
        // Log.i(TAG, "surfaceDestroyed: stopping camera Source"); 

        // cameraSource.release(); 
      } 
     }); 

     barcodeDetector.setProcessor(new Detector.Processor<Barcode>() { 
      @Override 
      public void release() { 
       Log.i(TAG, "release: "); 
      } 

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

       if (barCodes.size() != 0) { 

        Log.i(TAG, "received a Barcode"); 
        barcodeInfo.post(new Runnable() { // Use the post method of the TextView 
         public void run() { 
          barcodeInfo.setText(barCodes.valueAt(0).displayValue); 

         } 
        }); 
        Gson g = new Gson(); 
        try { 
         barCodeData = g.fromJson(barCodes.valueAt(0).rawValue, AccessPointCredentials.class); 
        } catch (Exception e) { 
         barCodeData = new AccessPointCredentials(); 
         barCodeData.setSsid(barCodes.valueAt(0).rawValue); 
         barCodeData.setPass(null); 
         e.printStackTrace(); 
        } 

        connectToWifi(barCodeData); 

        // CameraSource.release causes app to freeze 

        // cameraSource.release(); 
       } 
      } 
     }); 
    } 

    private void connectToWifi(final AccessPointCredentials credentials) { 

       //wificonnect code 

    } 

} 
+1

Nie jestem pewien, ale należy pamiętać, że istnieje otwarta kopia źródłem CameraSource że można spróbować, jeśli chcesz kopać w to dalej: https://github.com/googlesamples/android-vision /blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java#L322 – pm0733464

+0

Próbowałem wywoływać 'cameraSoutce. release() 'w dwóch miejscach, w których jest skomentowany (w' surfaceDestroyed() 'i' receiveDetections() ') – Lonergan6275

Odpowiedz

7

minęło 3 miesiące, ale po prostu natknął się na ten sam problem i zrozumieć. Kod wewnątrz metody receiveDetections działa w innym wątku, więc jeśli chcesz zrobić coś, co musi wątku UI trzeba dodawać go z Handler:

Handler handler = new Handler(Looper.getMainLooper()); 
handler.post(new Runnable() { 
    @Override 
    public void run() { 
     cameraSource.release(); 
    } 
}); 
+0

Dzięki za odpowiedź sprawdzę to, gdy dostanę szansę. – Lonergan6275

+1

Po wielu godzinach frustrujących awarii, mogę rzeczywiście potwierdzić, że jest to problem z wątkiem. Z ursing^^ ten kod lub używając '' 'view.post (new Runnable() {cameraSource.release()})' '' możesz to naprawić – Spidfire

0

Heyo, żadnych aktualizacji? Właśnie napotkałem podobny problem, staram się radzić sobie z tymi metodami release, ale nie działają. Znalazłem tylko szybką naprawę/obejście problemu. Chciałbym mieć eleganckie rozwiązanie.

Moja sprawa to, że użytkownik aplikacji może zeskanować kod QR, a następnie dokonać płatności.

MainActivity

  1. menu szuflady (https://github.com/mikepenz/MaterialDrawer)
  2. Fragment pojemnik (zmiana fragmenty, gdy użytkownik kliknie w menu szuflady)

wszystkie inne moje poglądy są Fragment/ListFragment

ScanMainController

  1. BarcodeDetector
  2. CameraSource
  3. SurfaceView

Mój scenariusz jest podobny do tego, raz skanowany kod QR, wciskam do innej strony do wykorzystania do dokonania płatności. Ale muszę znaleźć sposób, aby zatrzymać skaner QRCode, ponieważ chcę tylko, aby ten jeden receiveDetections był wywoływany tylko raz. W iOS ustawiałem delegate to nil, który działa tak samo jak cameraSource.release(); w systemie Android. Ale potem nie mogę znaleźć odpowiedniej pozycji, aby zadzwonić do metody release().

Jeśli proaktywnie zadzwonię pod numer release(), to gdy użytkownik chce przejść do innej strony poprzez kliknięcie menu szuflady, moje zatwierdzenie FragmentTransaction zostanie uruchomione, gdy cała aplikacja zawiesza się. A potem pojawi się system Android, powiedz mi, że aplikacja nie odpowiada.

Szybko naprawiłem, dodając flagę "boolean" wewnątrz "receiveDetections", aby zagwarantować, że popchnę widok tylko raz. To działa. Ale szukam bardziej eleganckiego sposobu i "właściwego" sposobu na zrobienie tego.

Dzięki