2017-07-09 71 views
0

我有一個活動,在開始時調用意圖啓動相機應用程序。相機應該拍攝一張照片,保存到本地系統,並將其呈現在圖像視圖中。相片的拍攝然而,當我得到這個消息:Android將圖像保存到文件系統

E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /external_storage_root/Pictures/HelloCamera/IMG_20170709_221239.jpg (No such file or directory) 

此消息時拋出

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

的previewCapturedImage()方法

這裏面如下的代碼

我有以下活動

package it.cosmopolitans.around.boundary; 


    import java.io.File; 
    import java.text.SimpleDateFormat; 
    import java.util.Date; 
    import java.util.Locale; 

    import android.Manifest; 
    import android.content.Intent; 
    import android.content.pm.PackageManager; 
    import android.graphics.Bitmap; 
    import android.graphics.BitmapFactory; 
    import android.net.Uri; 
    import android.os.Bundle; 
    import android.os.Environment; 
    import android.provider.MediaStore; 
    import android.support.v4.app.ActivityCompat; 
    import android.support.v4.content.FileProvider; 
    import android.support.v7.app.AppCompatActivity; 
    import android.util.Log; 
    import android.view.View; 
    import android.widget.ImageView; 
    import android.widget.Toast; 

    import it.cosmopolitans.around.R; 

public class ImageTakenActivity extends AppCompatActivity { 

// Activity request codes 
private static final int CAMERA_CAPTURE_IMAGE_REQUEST_CODE = 100; 
public static final int PERMISSIONS_MULTIPLE_REQUEST = 123; 

public static final int MEDIA_TYPE_IMAGE = 1; 

private static final String IMAGE_DIRECTORY_NAME = "HelloCamera"; 

private Uri fileUri; // file url to store image/video 

private ImageView imgPreview; 
private boolean dir_perm; 
private boolean cam_perm; 


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

    imgPreview = (ImageView) findViewById(R.id.imageTaken); 


    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_MULTIPLE_REQUEST); 


    //if( dir_perm == true) 
     captureImage(); 

    // Checking camera availability 
    if (!isDeviceSupportCamera()) { 
     Toast.makeText(getApplicationContext(), 
       "Sorry! Your device doesn't support camera", 
       Toast.LENGTH_LONG).show(); 
     // will close the app if the device does't have camera 
     finish(); 
    } 
} 

/** 
* Checking device has camera hardware or not 
* */ 
private boolean isDeviceSupportCamera() { 
    if (getApplicationContext().getPackageManager().hasSystemFeature(
      PackageManager.FEATURE_CAMERA)) { 
     // this device has a camera 
     return true; 
    } else { 
     // no camera on this device 
     return false; 
    } 
} 

/** 
* 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(); 
    } 
} 

/** 
* ------------ Helper Methods ---------------------- 
* */ 

public void requestStoragePermission() { 
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) { 
     //If the user has denied the permission previously your code will come to this block 
     //Here you can explain why you need this permission 
     //Explain here why you need this permission 
    } 
} 


/** 
* Creating file uri to store image/video 
*/ 
public Uri getOutputMediaFileUri(int type) { 
    //return Uri.fromFile(getOutputMediaFile(type)); 
    return FileProvider.getUriForFile(this, "it.cosmopolitans.fileprovider", getOutputMediaFile(type)); 
} 

/** 
* returning image/video 
*/ 
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.d(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 if (type == MEDIA_TYPE_VIDEO) { 
     mediaFile = new File(mediaStorageDir.getPath() + File.separator 
       + "VID_" + timeStamp + ".mp4"); 
    } else { 
     return null; 
    } 

    return mediaFile; 
} 

    @Override 
    public void onRequestPermissionsResult(int requestCode, 
    String permissions[], int[] grantResults) { 
     switch (requestCode) { 
      case PERMISSIONS_MULTIPLE_REQUEST: 
       if (grantResults.length > 0) { 
        boolean cameraPermission = grantResults[1] == PackageManager.PERMISSION_GRANTED; 
        boolean readExternalFile = grantResults[0] == PackageManager.PERMISSION_GRANTED; 

        if(cameraPermission && readExternalFile) 
        { 
         cam_perm = true; 
         dir_perm = true; 
        } else { 
         Toast.makeText(this, "permission rejected", Toast.LENGTH_SHORT).show(); 
        } 
       } 
       break; 
     } 
    } 



} 

我在清單

<provider 
     android:name="android.support.v4.content.FileProvider" 
     android:authorities="it.cosmopolitans.fileprovider" 
     android:exported="false" 
     android:grantUriPermissions="true"> 
     <meta-data 
      android:name="android.support.FILE_PROVIDER_PATHS" 
      android:resource="@xml/file_paths"/> 
    </provider> 

和下列文件路徑如下提供商

<external-path name="external_storage_root" path="./" /> 

回答

0

簡單而緩慢的解決辦法是更換:

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

有:

final Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(fileUri), options); 

兩個性能改進可以使:

  1. 守住File代替Uri,然後用FiledecodeFile()

  2. 使用的圖像加載庫(滑翔,畢加索等),這將做你的圖像解碼和背景線程上的磁盤I/O

+0

謝謝你的工作!經過一點改變,即: final Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver()。openInputStream(fileUri)); 但是我沒有得到你答案的第二部分。對不起,我是Android的新手。我應該做1和2在一起還是相互排斥?特別是我不明白第一個 – QuasarLex

+0

@QuasarLex:你應該兩個都做?理想的情況是,雖然#2更重要。至於#1,你抓住'fileUri'並用它來加載圖像。在這種情況下,你知道圖像是你自己的,在一個文件中。執行文件I/O比通過FileProvider執行相同的文件I/O要快。然而,這要求你保存'File',從中''Uri',而不是(或除了)'fileUri'本身。 – CommonsWare

+0

@QuasarLex:[FWIW,這裏是一個示例應用程序](https://github.com/commonsguy/cw-omnibus/tree/master/Camera/FileProvider),顯示使用'ACTION_IMAGE_CAPTURE'和'FileProvider'。在我的情況下,我使用'ACTION_VIEW'' Intent'顯示圖像,而不是將其加載到'ImageView'中。 – CommonsWare

相關問題