2016-01-13 119 views
1

我正在創建一個基本應用程序,它啓動相機活動,然後檢索單擊的圖像。從API 22升級到23時出錯:FileNotFoundException:**文件完整路徑**打開失敗:EACCES(權限被拒絕)

我在清單文件所需的權限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 

我的問題是應用程序API級別是工作的罰款22.我的手機更新到23級前幾天和現在相同的源代碼是給我這個錯誤:

E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /storage/emulated/0/Pictures/SAT Practice App/IMG_20160113_123753.jpg: open failed: EACCES (Permission denied)

有很多的計算器類似的問題,但大多隻談授予我已經在我的清單的權限。

我親自檢查了該文件夾,發現該文件存在。我可能會錯過什麼?

這裏是我的活動類的參考:

public class MainActivity extends Activity { 

    // Activity request codes 
    private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100; 
    public static final int MEDIA_TYPE_IMAGE = 1; 

    // directory name to store captured images 
    private static final String IMAGE_DIRECTORY_NAME = "SAT Practice"; 

    private Uri fileUri; // file url to store image 
    private ImageView imgPreview; 
    private Button btnCapturePicture; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     imgPreview = (ImageView) findViewById(R.id.imgPreview); 
     btnCapturePicture = (Button) findViewById(R.id.btnCapturePicture); 

     /** 
     * Capture image button click event 
     */ 
     btnCapturePicture.setOnClickListener(new View.OnClickListener() { 

      @Override 
      public void onClick(View v) { 
       // capture picture 
       captureImage(); 
      } 
     }); 
    } 

    /** 
    * Capturing Camera Image will lauch camera app requrest image capture 
    */ 
    private void captureImage() { 
     Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 

     fileUri = getOutputMediaFileUri(MEDIA_TYPE_IMAGE); 

     intent.putExtra(MediaStore.EXTRA_OUTPUT, fileUri); 

     // start the image capture Intent 
     startActivityForResult(intent, CAMERA_CAPTURE_IMAGE_REQUEST_CODE); 
    } 

    /** 
    * Here we store the file url as it will be null after returning from camera 
    * app 
    */ 
    @Override 
    protected void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 

     // save file url in bundle as it will be null on scren orientation 
     // changes 
     outState.putParcelable("file_uri", fileUri); 
    } 

    @Override 
    protected void onRestoreInstanceState(Bundle savedInstanceState) { 
     super.onRestoreInstanceState(savedInstanceState); 

     // get the file url 
     fileUri = savedInstanceState.getParcelable("file_uri"); 
    } 


    /** 
    * Receiving activity result method will be called after closing the camera 
    * */ 
    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     // if the result is capturing Image 
     if (requestCode == CAMERA_CAPTURE_IMAGE_REQUEST_CODE) { 
      if (resultCode == RESULT_OK) { 
       // successfully captured the image 
       // display it in image view 
       previewCapturedImage(); 
      } else if (resultCode == RESULT_CANCELED) { 
       // user cancelled Image capture 
       Toast.makeText(getApplicationContext(),"User cancelled image capture", Toast.LENGTH_SHORT).show(); 
      } else { 
       // failed to capture image 
       Toast.makeText(getApplicationContext(),"Sorry! Failed to capture image", Toast.LENGTH_SHORT).show(); 
      } 
     } 
    } 

    /** 
    * Display image from a path to ImageView 
    */ 
    private void previewCapturedImage() { 
     try { 
      imgPreview.setVisibility(View.VISIBLE); 

      // bimatp factory 
      BitmapFactory.Options options = new BitmapFactory.Options(); 

      // downsizing image as it throws OutOfMemory Exception for larger 
      // images 
      options.inSampleSize = 8; 

      final Bitmap bitmap = BitmapFactory.decodeFile(fileUri.getPath(), 
        options); 

      imgPreview.setImageBitmap(bitmap); 
     } catch (NullPointerException e) { 
      e.printStackTrace(); 
     } 
    } 

    /** 
    * Creating file uri to store image 
    */ 
    public Uri getOutputMediaFileUri(int type) { 
     return Uri.fromFile(getOutputMediaFile(type)); 
    } 

    /** 
    * returning image 
    */ 
    private static File getOutputMediaFile(int type) { 

     // External sdcard location 
     File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),IMAGE_DIRECTORY_NAME); 

     // Create the storage directory if it does not exist 
     if (!mediaStorageDir.exists()) { 
      if (!mediaStorageDir.mkdirs()) { 
       Log.i(IMAGE_DIRECTORY_NAME, "Oops! Failed create "+ IMAGE_DIRECTORY_NAME + " 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; 
     } 
     return mediaFile; 
    } 
} 

回答

2

所以,喬恩指出,對於API級別23和更高的,這裏的文檔是這麼說:

If the device is running Android 6.0 or higher, and your app's target SDK is 23 or higher: The app has to list the permissions in the manifest, and it must request each dangerous permission it needs while the app is running.

this答案,我們可以看到危險的權限列表(如讀取/寫入外部存儲,日曆,位置訪問等)。就我而言,我的危險權限是讀取和寫入外部存儲。因此,在我clicklistener啓動相機,我問用戶的權限爲:

int MY_PERMISSIONS_REQUEST_READ_AND_WRITE_EXTERNAL_STORAGE; 

btnCapturePicture.setOnClickListener(new View.OnClickListener() { 

     @Override 
     public void onClick(View v) { 
      if((ContextCompat.checkSelfPermission(MainActivity.this, 
        Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) 
        || (ContextCompat.checkSelfPermission(MainActivity.this, 
        Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) 

      { 
       ActivityCompat.requestPermissions 
         (MainActivity.this, new String[]{ 
           Manifest.permission.READ_EXTERNAL_STORAGE, 
           Manifest.permission.WRITE_EXTERNAL_STORAGE 
         },MY_PERMISSIONS_REQUEST_READ_AND_WRITE_EXTERNAL_STORAGE); 
      } 
//captureImage() method will start the camera. All reading/writing stuff is implemented in this method 
      captureImage(); 
     } 
    }); 

當應用程序調用requestPermissions(),系統顯示標準對話框向用戶詢問是否允許權限或沒有。

+0

我描述獲取此錯誤變量「MY_PERMISSIONS_REQUEST_READ_AND_WRITE_EXTERNAL_STORAGE」可能尚未初始化。它應該初始化爲什麼? – moberme

+0

@moberme你必須用一些數字初始化它..沒關係。 – Suisse

+0

@Akeshwar每次都要求允許,我們如何檢測到我們已經有一次允許? – Suisse

0

至於user5038993已經爲目標的SDK 23或更高,我們必須採取的權限讀取和寫入device..once你點擊允許,你可以做你的東西,任何東西......

@Override 
public void onClick(View v) { 
    if((ContextCompat.checkSelfPermission(MainActivity.this,         
      Manifest.permission.READ_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED)  
       || (ContextCompat.checkSelfPermission(MainActivity.this, 
       Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) 

     { 
      ActivityCompat.requestPermissions 
        (MainActivity.this, new String[]{ 
          Manifest.permission.READ_EXTERNAL_STORAGE, 
          Manifest.permission.WRITE_EXTERNAL_STORAGE 
        },MY_PERMISSIONS_REQUEST_READ_AND_WRITE_EXTERNAL_STORAGE); 
     } 
} 
相關問題