How to convert a content Uri into a File

I know there are a ton of questions about this exact topic, but after spending two days reading and trying them, none seamed to fix my problem.

This is my code:

I launch the ACTION_GET_CONTENT in my onCreate()

Intent selectIntent = new Intent(Intent.ACTION_GET_CONTENT);
        selectIntent.setType("audio/*");
        startActivityForResult(selectIntent, AUDIO_REQUEST_CODE);

retrieve the Uri in onActivityResult()

@Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == AUDIO_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
            if ((data != null) && (data.getData() != null)) {
                audio = data.getData();
            }
        }
    }

pass the Uri to another activity and retrieve it

Intent debugIntent = new Intent(this, Debug.class);
            Bundle bundle = new Bundle();
            bundle.putString("audio", audio.toString());
            debugIntent.putExtras(bundle);
            startActivity(debugIntent);

Intent intent = this.getIntent();
        Bundle bundle = intent.getExtras();
        audio = Uri.parse((String) bundle.get("audio"));

The I have implemented this method based on another SO answer. To get the actual Path of the Uri

public static String getRealPathFromUri(Activity activity, Uri contentUri) {
        String[] proj = { MediaStore.Audio.Media.DATA };
        Cursor cursor = activity.managedQuery(contentUri, proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    }

and in the Debug activity's onCreate() I try to generate the file:

File audioFile = new File(getRealPathFromUri(this, audio));

This is how the error looks like:

Caused by: java.lang.NullPointerException at java.io.File.(File.java:262) at com.dancam.lietome.Debug.onCreate(Debug.java:35)

When I run the app I get a NPE on this last line. The audio Uri, isn't NULL though so I don't understand from what it is caused.

I'd really appreciate if you helped me out.

This is the library I'm trying to work with.

Note: I know exactly what NPE is, but even debugging I couldn't figure out from what it is caused in this specific case.

3 answers

  • answered 2017-08-12 10:20 nivesh shastri

    Daniele, you can get path of file directly from data like below in onActivityResult():

    String gilePath = data.getData().getPath();
    

    Try this, i am waiting for your response.

  • answered 2017-08-12 10:33 isabsent

    Try to get path from your contentUri with this utility class under debug and may be you will find what problem appears in your case.

    package com.jetico.bestcrypt.util;
    
    import android.annotation.SuppressLint;
    import android.content.ContentUris;
    import android.content.Context;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Build;
    import android.os.Environment;
    import android.provider.DocumentsContract;
    import android.provider.MediaStore;
    
    import java.net.URISyntaxException;
    
    public class PathUtil {
        /*
         * Gets the file path of the given Uri.
         */
        @SuppressLint("NewApi")
        public static String getPath(Context context, Uri uri) throws URISyntaxException {
            final boolean needToCheckUri = Build.VERSION.SDK_INT >= 19;
            String selection = null;
            String[] selectionArgs = null;
            // Uri is different in versions after KITKAT (Android 4.4), we need to deal with different Uris.
            if (needToCheckUri && DocumentsContract.isDocumentUri(context.getApplicationContext(), uri)) {
                if (isExternalStorageDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    return Environment.getExternalStorageDirectory() + "/" + split[1];
                } else if (isDownloadsDocument(uri)) {
                    final String id = DocumentsContract.getDocumentId(uri);
                    uri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
                } else if (isMediaDocument(uri)) {
                    final String docId = DocumentsContract.getDocumentId(uri);
                    final String[] split = docId.split(":");
                    final String type = split[0];
                    if ("image".equals(type)) {
                        uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    }
                    selection = "_id=?";
                    selectionArgs = new String[]{ split[1] };
                }
            }
            if ("content".equalsIgnoreCase(uri.getScheme())) {
                String[] projection = { MediaStore.Images.Media.DATA };
                Cursor cursor;
                try {
                    cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                    if (cursor != null) {
                        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
                        if (cursor.moveToFirst())
                            return cursor.getString(column_index);
                    }
                } catch (Exception e) {
                }
            } else if ("file".equalsIgnoreCase(uri.getScheme())) {
                return uri.getPath();
            }
            return null;
        }
    
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is ExternalStorageProvider.
         */
        public static boolean isExternalStorageDocument(Uri uri) {
            return "com.android.externalstorage.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is DownloadsProvider.
         */
        public static boolean isDownloadsDocument(Uri uri) {
            return "com.android.providers.downloads.documents".equals(uri.getAuthority());
        }
    
        /**
         * @param uri The Uri to check.
         * @return Whether the Uri authority is MediaProvider.
         */
        public static boolean isMediaDocument(Uri uri) {
            return "com.android.providers.media.documents".equals(uri.getAuthority());
        }
    }
    

    Example of usage:

    try {
        PathUtil.getPath(YourActivity.this, contentUri);
    } catch (URISyntaxException e) {
        e.printStackTrace();
    }
    

  • answered 2017-08-12 11:01 CommonsWare

    pass the Uri to another activity and retrieve it

    Your other activity does not necessarily have rights to work with the content identified by the Uri. Add FLAG_GRANT_READ_URI_PERMISSION to the Intent used to start that activity, and pass the Uri via the "data" facet of the Intent (setData()), not an extra.

    To get the actual Path of the Uri

    First, there is no requirement that the Uri that you get back be from the MediaStore.

    Second, managedQuery() has been deprecated for six years.

    Third, there is no requirement that the path that MediaStore has be one that you can use. For example, the audio file might be on removable storage, and while MediaStore can access it, you cannot.

    How to convert a content Uri into a File

    On a background thread:

    • Get a ContentResolver by calling getContentResolver() on a Context
    • Call openInputStream() on the ContentResolver, passing in the Uri that you obtained from ACTION_GET_CONTENT, to get an InputStream on the content identified by the Uri
    • Create a FileOutputStream on some File, where you want the content to be stored
    • Use Java I/O to copy the content from the InputStream to the FileOutputStream, closing both streams when you are done