`getExternalStorageDirectory()` issue - Android

2019-06-12 11:06发布

问题:

I'm writing an android application that takes some pictures and would like to save them all in a unique directory associated to my application.

This directory should be accessible from the standard Gallery, in such a way that the user can later (when application is not necessarily running) check the pictures that were taken.

My problem is that every different phone vendor, with a different android version, has different paths for gallery.As an example:

Environment.getExternalStorageDirectory() + Environment.DIRECTORY_PICTURES +"/myFolder"

will work on Samsung Galaxy Nexus running android 4.1.1, and on Asus Transformer Pad running android 4.0.3, but not on HTC Desire running android 2.3.5.

This will cause my application to crash when trying to save a new directory within the specified path, as stated below:

boolean success = false;
myFolder = new File( Environment.getExternalStorageDirectory() + Environment.DIRECTORY_PICTURES + "/myFolder" );

if( myFolder.exists() ){
//do nothing        
}else{

    success = dvaFolder.mkdir();

if( success ){
    // Do something on success
    /*
     * folder has been created
     */

} else {
    // Do something else on failure 
    /*
     * folder creation failed
     */
    throw new RuntimeException("File Error in writing new folder");
}
}

How can I write a directory that will be accessible in gallery for all different vendors and android versions?

NOTE:

Logcat isn't much useful, cause it just returns the run time Exception.

回答1:

I've had the same issue with the bluetooth folder, I created a two methods to search for the bluetooth folder on the phone, by traversing the whole file structure on the phone. The code I wrote is beneath, it is a bit dirty, but it works quite well in my case

public List<File> folderSearchBT(File src, String folder) {

    List<File> result = new ArrayList<File>();

    File[] filesAndDirs = src.listFiles();


    if (filesAndDirs != null && filesAndDirs.length > 0) {
        List<File> filesDirs = Arrays.asList(filesAndDirs);

        for (File file : filesDirs) {
            result.add(file); // always add, even if directory
            if (file.isDirectory()) {
                List<File> deeperList = folderSearchBT(file, folder);
                result.addAll(deeperList);
            }
        }
    }
    return result;
}

Use the method above in this method:

public String searchForGallery() {

    String splitchar = "/";
    File root = Environment.getExternalStorageDirectory();
    List<File> btFolder = null;
    String folder = "gallery"; //your foldername to search for..
    btFolder = folderSearchBT(root, folder);

    if(btFolder.size() < 1)
        Log.i("btFolder: ", "Empty");

    for (int i = 0; i < btFolder.size(); i++) {

        String g = btFolder.get(i).toString();

        String[] subf = g.split(splitchar);

        String s = subf[subf.length - 1].toUpperCase();

        boolean equals = s.equalsIgnoreCase(folder);

        if (equals)
            return g;
    }
    return null; //not found
}

By saying that the code is dirty, I mean that I could wrote it more compact and another issue by doing it this way: if there are two folders with the name bluetooth, I'm stuck..

I hope I understood your question right.



回答2:

Here is working code for taking picture and saving to external storage and another method for saving to 'files' directory on device. In my case I needed only one image (something.png) which will be always refreshed after user takes new picture.

Action when user clicks on button for camera:

ImageView productImageView = (ImageView) findViewById(R.id.imageView1);
static int RESULT_TAKE_PICTURE = 1;
String selectedImagePath;
Bitmap bitmap;
String imageName = "something.png";

public void cameraImageButton_onClick(View view) {
    Intent cameraIntent = new Intent(
            android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    String path = Environment.getExternalStorageDirectory()
            + File.separator + Environment.DIRECTORY_PICTURES;
    File dir = new File(path);
    if (!dir.exists()) {
        dir.mkdir();
    }
    dir = new File(path, imageName);
    cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(dir));
    startActivityForResult(cameraIntent, RESULT_TAKE_PICTURE);
}

Action which is performed on activity result:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == RESULT_TAKE_PICTURE && resultCode == RESULT_OK) {

        selectedImagePath = Environment.getExternalStorageDirectory()
                + File.separator + Environment.DIRECTORY_PICTURES
                + File.separator + imageName;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(selectedImagePath, options);
        options.inSampleSize = Calculator.calculateInSampleSize(options,
                254, 254);
        options.inJustDecodeBounds = false;
        bitmap = BitmapFactory.decodeFile(selectedImagePath, options);
        productImageView.setImageBitmap(bitmap);

        saveImage(bitmap, imageName);

    }

}

Bonus method for saving image to device in files directory if someone needs:

private void saveImage(Bitmap bitmap, String name) {
    String path = getApplicationContext().getFilesDir().toString()
            + File.separator;
    File dir = new File(path);

    if (!dir.exists()) {
        dir.mkdir();
    }

    path = path + name;
    dir = new File(path);

    try {
        dir.createNewFile();
        FileOutputStream fos = new FileOutputStream(dir);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
        fos.close();
        fos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }

}


回答3:

You should check that you have included the "WRITE_EXTERNAL_STORAGE" permission in your application Manifest, it could give such errors. Also, have you checked that the path does not simply look invalid by printing it?