简体   繁体   English

Android 7上的应用程序崩溃

[英]App crash on android seven

When I run my app on android 7 I the app crashes. 当我在android 7上运行我的应用程序时,我的应用程序崩溃了。 Android monitor throws this : Android监视器抛出此:

Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/picture.jpg exposed beyond app through ClipData.Item.getUri()

And code is 和代码是

   @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            switch (requestCode) {
                case REQUEST_WRITE_PERMISSION:
                    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        takePicture();
                    } else {
                        Toast.makeText(MainActivity.this, "Permission Denied!", Toast.LENGTH_SHORT).show();
                    }
            }
        }

        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == PHOTO_REQUEST && resultCode == RESULT_OK) {
                Toast.makeText(this,"CLICK ON THE TEXT TO SAVE THE DATA",Toast.LENGTH_LONG).show();
                launchMediaScanIntent();
                try {
                    Bitmap bitmap = decodeBitmapUri(this, imageUri);
                    if (detector.isOperational() && bitmap != null) {
                        Frame frame = new Frame.Builder().setBitmap(bitmap).build();
                        SparseArray<TextBlock> textBlocks = detector.detect(frame);
                        String blocks = "";
                        String lines = "";
                        String words = "";
                        for (int index = 0; index < textBlocks.size(); index++) {
                            //extract scanned text blocks here
                            TextBlock tBlock = textBlocks.valueAt(index);
                            blocks = blocks + tBlock.getValue() + "\n" + "\n";
                            for (Text line : tBlock.getComponents()) {
                                //extract scanned text lines here
                                lines = lines + line.getValue() + "\n";
                                for (Text element : line.getComponents()) {
                                    //extract scanned text words here
                                    words = words + element.getValue() + ", ";
                                }
                            }
                        }
                        if (textBlocks.size() == 0) {

                            scanResults.setText("Scan Failed: Found nothing to scan");
                        } else {
                            scanResults.setText(scanResults.getText() +   "\n");
                            scanResults.setText(scanResults.getText() + blocks + "\n");

                        }
                    } else {
                        scanResults.setText("Could not set up the detector!");
                    }
                } catch (Exception e) {
                    Toast.makeText(this, "Failed to load Image", Toast.LENGTH_SHORT)
                            .show();
                    Log.e(LOG_TAG, e.toString());
                }
            }
        }

        private void takePicture() {
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            File photo = new File(Environment.getExternalStorageDirectory(), "picture.jpg");
            imageUri = Uri.fromFile(photo);
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
            startActivityForResult(intent, PHOTO_REQUEST);
            scanResults.setText("");
        }

        @Override
        protected void onSaveInstanceState(Bundle outState) {
            if (imageUri != null) {
                outState.putString(SAVED_INSTANCE_URI, imageUri.toString());
                outState.putString(SAVED_INSTANCE_RESULT, scanResults.getText().toString());
            }
            super.onSaveInstanceState(outState);
        }

        private void launchMediaScanIntent() {
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            mediaScanIntent.setData(imageUri);
            this.sendBroadcast(mediaScanIntent);
        }

        private Bitmap decodeBitmapUri(Context ctx, Uri uri) throws FileNotFoundException {
            int targetW = 600;
            int targetH = 600;
            BitmapFactory.Options bmOptions = new BitmapFactory.Options();
            bmOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(ctx.getContentResolver().openInputStream(uri), null, bmOptions);
            int photoW = bmOptions.outWidth;
            int photoH = bmOptions.outHeight;

            int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
            bmOptions.inJustDecodeBounds = false;
            bmOptions.inSampleSize = scaleFactor;

            return BitmapFactory.decodeStream(ctx.getContentResolver()
                    .openInputStream(uri), null, bmOptions);
        }

        public void store_in_database(View view) {

            Intent i = new Intent(MainActivity.this , DbActivity.class);
            i.putExtra("message",scanResults.getText().toString());
            MainActivity.this.startActivity(i);


        }

Any help in the form of code would be great. 以代码形式提供的任何帮助都将非常有用。 I understand this may be due to the file system permissions related to android 7 . 我了解这可能是由于与android 7相关的文件系统权限。 Any explanation in the form of code is most welcomed. 欢迎以代码形式进行任何解释。 I am trying to access the camera and store the image into android database. 我正在尝试访问相机并将图像存储到android数据库中。

In nougat what you have to do is use FileProvider for path like this: 在牛轧糖中,您需要做的是使用FileProvider作为这样的路径:

  1. declare provider in manifest under application: 在申请中的清单中声明提供者:

      <application 
      ...> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.safetynetwork.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider> </application> 
  2. Create xml package under resource and add provider_path.xml there. 在资源下创建xml包,并在其中添加provider_path.xml

     <paths> <external-path name="SN" path="Android/data/com.packagename/files/Pictures/SN/"/> </paths> 
  3. now set path for image that you mention in provider_path.xml 现在设置您在provider_path.xml中提到的图像的路径

     public Uri getOutputMediaFileUri(int type) { return Uri.fromFile(getOutputMediaFile(type)); } /** * returning image / video */ private File getOutputMediaFile(int type) { // External sdcard location File mediaStorageDir = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "SN"); // Create the storage directory if it does not exist if (!mediaStorageDir.exists()) { if (!mediaStorageDir.mkdirs()) { Log.d("FileName::", "Oops! Failed create " + "SN" + " directory"); return null; } } // Create a media file name String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); File mediaFile; if (type == MEDIA_TYPE_IMAGE) { mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg"); } else { return null; } mCurrentPhotoPath = mediaFile.getAbsolutePath(); return mediaFile; } 
  4. now pick photo like this: 现在选择这样的照片:

    private void selectImage() { 私人无效selectImage(){

      final CharSequence[] options = {"Camera", "Choose from Gallery"}; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Add Photo!"); builder.setItems(options, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int item) { if (options[item].equals("Camera")) { isCamera = 1; if (checkandRequestPermission()) { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); fileUri = FileProvider.getUriForFile(ActivityModifyProfile.this, getPackageName() + ".provider", getOutputMediaFile(MEDIA_TYPE_IMAGE)); intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); } else { fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); } startActivityForResult(intent, 1); } } else if (options[item].equals("Choose from Gallery")) { isCamera = 0; if (checkandRequestPermission()) { Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(intent, 2); } } } }); builder.show(); } 
  5. set path to bitmap like this: 像这样设置位图的路径:

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == 1) { Log.d("myPath1:", mCurrentPhotoPath); Log.d("myPath2:", fileUri.getPath()); try { BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { bitmap1 = BitmapFactory.decodeFile(mCurrentPhotoPath, bitmapOptions); } else { bitmap1 = BitmapFactory.decodeFile(fileUri.getPath(), bitmapOptions); } imgProfile.setImageBitmap(bitmap1); } catch (Exception e) { e.printStackTrace(); } } else if (requestCode == 2) { Uri selectedImage = data.getData(); String[] filePath = {MediaStore.Images.Media.DATA}; Cursor c = getContentResolver().query(selectedImage, filePath, null, null, null); c.moveToFirst(); int columnIndex = c.getColumnIndex(filePath[0]); imagePath = c.getString(columnIndex); c.close(); bitmap1 = (BitmapFactory.decodeFile(imagePath)); imgProfile.setImageBitmap(bitmap1); } } } 

Add this code in MainActivity.java in oncreate() 在oncreate()的MainActivity.java中添加此代码

 if (ContextCompat.checkSelfPermission(GoogleMapsActivity.this,
            android.Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {

        // Should we show an explanation?
        if ActivityCompat.shouldShowRequestPermissionRationale(GoogleMapsActivity.this,
                android.Manifest.permission.READ_EXTERNAL_STORAGE)) {

        } else {

            ActivityCompat.requestPermissions(GoogleMapsActivity.this,
                    new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        }
    }

Finally I got the app running successfully . 最后,我成功运行了该应用程序。

1.Declare provider in manifest in application. 1.在应用程序清单中声明提供程序。

 <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.abhijeet.demo11.MainActivity.GenericFileProvider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths"/>
        </provider>

2 . 2。 Create xml package under resource and add provider_path.xml there. 在资源下创建xml包,并在其中添加provider_path.xml。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>

3 . 3。 Change 更改

 imageUri = Uri.fromFile(photo);

to

  imageUri = FileProvider.getUriForFile(getApplicationContext(),"com.example.abhijeet.demo11.MainActivity.GenericFileProvider",photo);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM