Сбой разрешения времени выполнения камеры

Я создал отдельный класс для предоставления разрешения. И теперь я хочу предоставить разрешение своему приложению камеры при запуске. Когда я запускаю приложение в первый раз, у меня возникает ошибка сбоя, затем отображается диалоговое окно разрешения, и я могу предоставить разрешение, а затем мое приложение упало. После того, как я снова вхожу в приложение, они работают. Как я могу исправить этот сбой разрешения проблемы первого запуска? Для камеры я использовал примеры с сайта разработчика Android. Разрешение в манифесте добавлено.

Мой класс разрешений

public abstract class AbsRuntimePermission extends Activity {
    private SparseIntArray mErrorString;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mErrorString = new SparseIntArray();

    }

    public abstract void onPermissionsGranted(int requestCode);

    public void requestAppPermissions(final String[]requestedPermissions, final int stringId, final int requestCode) {
        mErrorString.put(requestCode, stringId);

        int permissionCheck = PackageManager.PERMISSION_GRANTED;
        boolean showRequestPermissions = false;
        for(String permission: requestedPermissions) {
            permissionCheck = permissionCheck + ContextCompat.checkSelfPermission(this, permission);
            showRequestPermissions = showRequestPermissions || ActivityCompat.shouldShowRequestPermissionRationale(this, permission);
        }

        if (permissionCheck!=PackageManager.PERMISSION_GRANTED) {
            if(showRequestPermissions) {
                Snackbar.make(findViewById(android.R.id.content), stringId, Snackbar.LENGTH_INDEFINITE).setAction("GRANT", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        ActivityCompat.requestPermissions(AbsRuntimePermission.this, requestedPermissions, requestCode);
                    }
                }).show();
            } else {
                ActivityCompat.requestPermissions(this, requestedPermissions, requestCode);
            }
        } else {
            onPermissionsGranted(requestCode);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        int permissionCheck = PackageManager.PERMISSION_GRANTED;
        for(int permisson : grantResults) {
            permissionCheck = permissionCheck + permisson;
        }

        if( (grantResults.length > 0) && PackageManager.PERMISSION_GRANTED == permissionCheck) {
            onPermissionsGranted(requestCode);
        } else {
            //Display message when contain some Dangerous permisson not accept
            Snackbar.make(findViewById(android.R.id.content), mErrorString.get(requestCode),
                    Snackbar.LENGTH_INDEFINITE).setAction("ENABLE", new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent i = new Intent();
                    i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    i.setData(Uri.parse("package:" + getPackageName()));
                    i.addCategory(Intent.CATEGORY_DEFAULT);
                    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
                    i.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                    startActivity(i);
                }
            }).show();
        }
    }
}

Моя активность камеры

public class CameraActivity extends AbsRuntimePermission {

    private Camera mCamera;
    private CameraPreview mPreview;
    private static final int REQUEST_PERMISSION = 10;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);

        requestAppPermissions(new String[]{
                        Manifest.permission.CAMERA},
                R.string.msg,REQUEST_PERMISSION);

        // Create an instance of Camera
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = findViewById(R.id.camera_preview);
        preview.addView(mPreview);
    }

    @Override
    public void onPermissionsGranted(int requestCode) {
        //Do anything when permisson granted
        Toast.makeText(getApplicationContext(), "Permission granted", Toast.LENGTH_LONG).show();
    }


    @Override
    public void onPause() {
        super.onPause();
        // Stop camera access
        releaseCamera();
    }

    public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable
    }

  private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
}

предварительный просмотр камеры

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        //mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }


    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

трассировки стека

09-14 11:02:02.414 5592-5592/com.nopermissions.ivan.camerawithoutpermissions_01 E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.nopermissions.ivan.camerawithoutpermissions_01, PID: 5592
    java.lang.NullPointerException: Attempt to invoke virtual method 'void android.hardware.Camera.setPreviewDisplay(android.view.SurfaceHolder)' on a null object reference
        at com.nopermissions.ivan.camerawithoutpermissions_01.CameraPreview.surfaceCreated(CameraPreview.java:35)
        at android.view.SurfaceView.updateWindow(SurfaceView.java:656)
        at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:172)
        at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1013)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2542)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1537)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:959)
        at android.view.Choreographer.doCallbacks(Choreographer.java:734)
        at android.view.Choreographer.doFrame(Choreographer.java:670)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:945)
        at android.os.Handler.handleCallback(Handler.java:751)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6776)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)

Разместите трассировку стека.

Gabe Sechan 13.09.2018 20:57

вы должны отправить трассировку стека, но из ваших заметок я могу сказать, что одна строка в пути выполнения вашего кода, когда у вас нет разрешения, вызывает исключение, например, в вашем requestAppPermissions, потому что, когда у вас есть разрешение, этот метод не будет вызываться.

ygngy 13.09.2018 21:01

вот трассировка стека

TesterIB 14.09.2018 11:04

Похоже, у вас нет камеры. Попробуйте зарегистрировать в коде следующее место: public static Camera getCameraInstance () {Camera c = null; попробуйте {c = Camera.open (); // пытаемся получить экземпляр камеры} catch (Exception e) {Log.d (TAG, "Камера недоступна:" + e.getMessage ()); } return c; // возвращает null, если камера недоступна}

Access Denied 14.09.2018 11:11

также удалите mHolder из вашего кода и подпишитесь на события держателя при surfaceCreated.

Access Denied 14.09.2018 11:18
0
5
590
1

Ответы 1

в CameraActivity ... mCamera = getCameraInstance(); возвращает NULL.

вы можете предотвратить сбой, проверив if(mCamera != null) перед продолжением.

if(mCamera != null) {
    mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = findViewById(R.id.camera_preview);
    preview.addView(mPreview);
}

код также должен называться onRequestPermissionsResult ...

поэтому самым элегантным было бы поместить его в собственный метод.

Другие вопросы по теме