In a section of an application I'm building, there's an embedded zxing qr scanner, and I'm using it inside a fragment.
If the app has not granted Manifest.permission.CAMERA
permission yet, it asks for the permission and then continue with enabling the scanner.
The problem is, I call barcodeView.resume()
inside onResume()
and I ask for the permission in onStart()
. So it should ask for the permission first and after that call barcodeView.resume()
inside the onResume()
. But apparently the opposite happens, if the app is not granted the permission yet, it throws this exception
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.journeyapps.barcodescanner.DecoratedBarcodeView.resume()' on a null object reference
How come is that happening ? Isn't onResume()
called after onStart()
not before?
Here's my fragment code:
package com.lab.rafael.smartattendance;
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.zxing.ResultPoint;
import com.google.zxing.client.android.BeepManager;
import com.journeyapps.barcodescanner.BarcodeCallback;
import com.journeyapps.barcodescanner.BarcodeResult;
import com.journeyapps.barcodescanner.DecoratedBarcodeView;
import java.util.List;
public class TakeAttendanceFragment extends Fragment {
private final int CAMERA_PERM_REQUEST = 0;
private static final String TAG = TakeAttendanceFragment.class.getSimpleName();
DecoratedBarcodeView barcodeView = null;
BeepManager beepManager = null;
String lastText;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_take_attendance, container, false);
}
@Override
public void onStart() {
super.onStart();
if(getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
if(ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(getActivity(), new String[] {Manifest.permission.CAMERA}, CAMERA_PERM_REQUEST);
} else {
startCamera();
}
}
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(requestCode == CAMERA_PERM_REQUEST) {
if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startCamera();
}
}
}
private void startCamera() {
try {
if(getView() != null) {
barcodeView = (DecoratedBarcodeView) getView().findViewById(R.id.barcode_scanner);
barcodeView.decodeContinuous(barcodeCallback);
beepManager = new BeepManager(getActivity());
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
private BarcodeCallback barcodeCallback = new BarcodeCallback() {
@Override
public void barcodeResult(BarcodeResult result) {
if(result.getText() == null || result.getText().equals(lastText)) return;
lastText = result.getText();
barcodeView.setStatusText(lastText);
beepManager.playBeepSoundAndVibrate();
}
@Override
public void possibleResultPoints(List<ResultPoint> resultPoints) {
}
};
public void onResume()
{
super.onResume();
barcodeView.resume();
}
public void onPause() {
super.onPause();
barcodeView.pause();
}
}
onStart is called before onResume, yes.
The Permission request dialog is not blocking, so the fragments lifecycles will continue when you ask for permissions.
So it'll go like this:
- onStart
- Request permission
- onResume (at this point the user hasn't granted permission yet).
You'll need to have a check in onResume to see if the barcodeView is not null and permission have been granted.
If the permission is granted, the onRequestPermissionsResult will be called immediately after onStart, as it's not async if the permission is granted, then this code would work fine.