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 上的应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章
UITableViewCell indexPathForCell:iOS 7 上的应用程序崩溃