Store video files on SD card in Android 5

2019-04-15 15:44发布

问题:

I'm recording video with the aid of android.media.MediaRecorder class, which accepts path string for output file (MediaRecorder.setOutputFile(String)), though there is a version of the method which accepts FileDescriptor.

I need to store huge video files, so I want to use SD card. In order to get path to relevant directory I use Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM). It turns out that resulting path is for the “emulated” storage (/sdcard/…) instead of real SD card (/sdcard1/ on my Xperia Z3 Compact, Android 5.1.1).

I tried to hardcode /sdcard1/ (as well as /storage/sdcard1) but get an IOException talking about permission deny. Of course, I have

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

I heard about huge changes in access to SD card after 4.4 (aka Storage Access Framework), but couldn't find simple and clear enough explanation on how to get things done in such a case. Any help on short and concise solution for this?

PS Solution with hardcoded path would be OK for me as I'm going to use this app only with my phone.

回答1:

This code should solve your problem:

 public String createVideoFilePath() {
        String time = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File[] pathsArray = getExternalFilesDirs(Environment.DIRECTORY_DCIM);

/Usually, pathArray[1] contains path to necessary folder on removable SD card. So we can generally use just pathArray[1] instead of searching necessary File in pathArray with for statement/

        for (File f : pathsArray) {
            if ((f != null) && (Environment.isExternalStorageRemovable(f))) {
                return f.getPath() + File.separator +"video_"+ time + ".mp4";
            }
        }

        return pathsArray[0].getPath() + File.separator +"video_"+ time + ".mp4";

    }

This method returns location of file on removable SD card or in emulated storage, if removable SD doesn't exist

Just use this method as a paramter of MediaRecorder.setOutputFile(String) Update: It is very important to say, that all files, which locate in folders, gotten with Context. getExternalFilesDirs(String typr) will be removed after uninstalling your app.



回答2:

So I had to go “full circle” with above mentioned Storage Access Framework.

Step 1: Request for file creation

Note: fileName below is literally name of a file itself, without full (desired) path to it. E.g. myvideo.mp4.

private void createFile(String fileName) {
    String mimeType = "video/mp4";
    Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);

    intent.addCategory(Intent.CATEGORY_OPENABLE);

    intent.setType(mimeType);
    intent.putExtra(Intent.EXTRA_TITLE, fileName);
    startActivityForResult(intent, WRITE_REQUEST_CODE /* is some random int constant*/);
}

Step 2: Callback for handling directory choice

After calling createFile (cf. step 1) a user will be supplied with a system dialog for choosing a directory where file will be stored. After they makes their choice the handler will be fired with desired URI for the new file. We can turn it into FileDescriptor and use corresponding version of MediaRecorder.setOutputFile.

@Override
public void onActivityResult(int requestCode, int resultCode,
                             Intent resultData) {

    if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        if (resultData != null) {
            URI outputFileUri = resultData.getData();
            FileDesriptor outputFileDescriptor = getContentResolver().openFileDescriptor(outputFileUri, "w").getFileDescriptor()
            mMediaRecorder.setOutputFile(outputFileDescriptor);
            mMediaRecorder.start();
        }
    }
}

This method should be implemented inside some Activity-class.

Room for improvement

So a user has to click Save in system menu each time they starts new video. It would be nice to restore pre-KitKat state when my application could decide the directory on its own. Considering my experience if using “professional” applications this indeed is possible. E.g. “ES Explorer” asks user to explicitly give permission for operations on SD card only once (using the alike system dialog).