11

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.

Daniele
  • 4,163
  • 7
  • 44
  • 95
  • @isabsent I don't see any result I get an NPE – Daniele Aug 12 '17 at 10:16
  • I see. Set breakpoint to each string in method `getRealPathFromUri(Activity activity, Uri contentUri)` and find out which string leads to NPE. I suppose `cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)` throws NPE. – isabsent Aug 12 '17 at 10:17
  • what do you need that `File` for? you have a `Uri`, just use it, and no, no need to pass a `String`, use `Intent#setData` instead – pskink Aug 12 '17 at 10:17
  • @pskink no I need a File, a Uri isn't working for me. – Daniele Aug 12 '17 at 10:18
  • @isabsent no particular String in the method is causing the NPE it happens always in the call line – Daniele Aug 12 '17 at 10:21
  • what for? why it isnt working for you? where do you want to use it? have you seen how many posts here use that `getRealPathFromUri` method without any success? – pskink Aug 12 '17 at 10:22
  • If so, set breakpoint inside of `getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)` method in Android sources and go ahead step by step (F8 in AS). – isabsent Aug 12 '17 at 10:24
  • @pskink for some paople the getRealPath seamed to work. Still how is it possible that there's no way to convert an Uri to File? It should be a pretty easy operation – Daniele Aug 12 '17 at 10:26
  • 1
    simply by using `ContentResolver` API - it has methods for opening any `content://` based `Uri` – pskink Aug 12 '17 at 10:43
  • @pskink Please show me in an answer how to use it. I never worked with Files before. I'd really appreciate that – Daniele Aug 12 '17 at 10:44
  • 1
    then try to read `ContentResolver` documentation, but you didnt answer my question: where do you want to use your audio `Uri`? there is a chance that you can do that even easier... – pskink Aug 12 '17 at 10:46
  • @pskink I need to use a function that has a File as a parameter. But I can't pass a file from an Activity to another. I need to pass a Uri. That's why I need to convert it later – Daniele Aug 12 '17 at 10:49
  • what function? what class do you mean? – pskink Aug 12 '17 at 10:51

3 Answers3

11

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
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 1
    but honestly i really doubt OP needs a `File` - most 3rd party libs when they have `File` param, they also accept `InputStream` as their input - infortunately OP didnt want to say where he wants to use it... – pskink Aug 12 '17 at 11:07
  • @pskink Please check the library in the edited question. There's no input stream constructor there, only one that gets a path and a name, and another that get's the whole file. I was thinking to use the one who had the file as a parameter. And thanks CommonsWare for the great and detailed answer – Daniele Aug 12 '17 at 11:12
  • @Daniele and have you seen where `mInFile` is used? only in one place: `FileInputStream fileStream = new FileInputStream(mInFile);`, so the easiest solution is just to add a new constructor that takes `InputStream` – pskink Aug 12 '17 at 11:16
  • Ok so it is an InputStream in the end. I only need to modify the constructor right? and then? what do I pass as an inputStream? The Uri itself? – Daniele Aug 12 '17 at 11:17
  • @Daniele please read CommonsWare answer - he says how to get `InputStream` from your `Uri` – pskink Aug 12 '17 at 11:19
  • That's right thanks. I'll implement this this afternoon – Daniele Aug 12 '17 at 11:21
  • created a new constructor with InputStream and all of this worked flawlessly thanks a lot guys – Daniele Aug 12 '17 at 16:23
0

I ran into same problem for Android Q, so I end up creating a new file and use input stream from content to fill that file Here's How I do it in kotlin:

private var pdfFile: File? = null

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (resultCode == Activity.RESULT_OK) {
            if (data != null) {
                when (requestCode) {
                    REQUEST_CODE_DOC -> {
                        data.data?.let {
                            if (it.scheme.equals("content")) {
                                val pdfBytes =
                                    (contentResolver?.openInputStream(it))?.readBytes()
                                pdfFile = File(
                                    getExternalFilesDir(null),
                                    "Lesson ${Calendar.getInstance().time}t.pdf"
                                )

                                if (pdfFile!!.exists())
                                    pdfFile!!.delete()
                                try {
                                    val fos = FileOutputStream(pdfFile!!.path)
                                    fos.write(pdfBytes)
                                    fos.close()
                                } catch (e: Exception) {
                                    Timber.e("PDF File", "Exception in pdf callback", e)
                                }
                            } else {
                                pdfFile = it.toFile()
                            }

                        }
                    }
                }
            }
        }
    }
Amin Keshavarzian
  • 3,646
  • 1
  • 37
  • 38
-1

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

String gilePath = data.getData().getPath();
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
nivesh shastri
  • 430
  • 2
  • 13