Android 7 上的应用程序崩溃

Posted

技术标签:

【中文标题】Android 7 上的应用程序崩溃【英文标题】:App crash on android seven 【发布时间】:2017-07-28 03:25:35 【问题描述】:

当我在 android 7 上运行我的应用程序时,我的应用程序崩溃了。 Android监视器抛出这个:

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

代码是

   @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);


        

任何以代码形式提供的帮助都会很棒。我知道这可能是由于与 android 7 相关的文件系统权限。任何以代码形式的解释都是最受欢迎的。我正在尝试访问相机并将图像存储到 android 数据库中。

【问题讨论】:

发布崩溃数据(logcat 输出) 请再次检查问题。我已经编辑了它 你需要使用 FileProvider ***.com/a/38858040/2819510 Open image in gallery with Android Nougat的可能重复 @RahulKhurana 非常感谢。它工作:) 【参考方案1】:

在 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);

        
    

【讨论】:

【参考方案2】:

在牛轧糖中,你要做的就是使用 FileProvider 来做这样的路径:

    在应用程序下的清单中声明提供者:

      <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>
    

    在resource下创建xml包,在里面添加provider_path.xml

    <paths>
        <external-path name="SN" path="Android/data/com.packagename/files/Pictures/SN/"/>
    </paths>
    

    现在为您在 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;
    
    

    现在选择这样的照片:

    private void 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();
    
    

    像这样设置位图的路径:

@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);
            
        
    

【讨论】:

【参考方案3】:

终于让应用成功运行了。

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 。在resource下创建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 .改变

 imageUri = Uri.fromFile(photo);

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

【讨论】:

以上是关于Android 7 上的应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Android 5.0.x 上的应用程序崩溃

UITableViewCell indexPathForCell:iOS 7 上的应用程序崩溃

如何停止通过 buildozer 制作的 android 上的 kivy 应用程序崩溃。这些在计算机上运行良好

android 2.3 上的推送通知崩溃。

android 5/L 上的 Valgrind 崩溃

在 android 中使用 5 到 7 天后,ionic 5 应用程序崩溃