4

So, I'm trying to load a simple .txt file like this:

    private void showFileChooser() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("text/plain");
    intent.addCategory(Intent.CATEGORY_OPENABLE);

    try {
        startActivityForResult(
                Intent.createChooser(intent, "Select a File to Upload"),
                FILE_SELECT_CODE);
    } catch (android.content.ActivityNotFoundException ex) {
        Toast.makeText(this, "Please install a File Manager.",
                Toast.LENGTH_SHORT).show();
    }
}

And of course, catching the result like this:

 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case FILE_SELECT_CODE:
            if (resultCode == RESULT_OK) {

                // Get the Uri of the selected file
                Uri uri = data.getData();

It works great on genymotion and on my device if I use a file explorer that I have installed (File explorer, see image abovew), now, If use the chooser directly like this:

enter image description here

It says it cannot find the specified file. (FileNotFoundException)

Now, I've realized that the URIs I get from these two file choosers are different

content://com.android.externalstorage.documents/document/primary%3ADownload%2Ffile.txt <- THIS DOESNT WORK (android built in explorer)

content://media/external/file/44751 <- THIS WORKS (custom explorer)

Does anyone have any idea why I'm getting different URIs for the SAME file.

EDIT: I tried to use a content resolver to get the file path from the URI like this:

public class Utils {

public static String getRealPathFromURI(Context context, Uri contentUri) {
    Cursor cursor = null;
    try {
        String[] proj = {MediaStore.Files.FileColumns.DATA};
        cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(proj[0]);
        cursor.moveToFirst();
        return cursor.getString(column_index);
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
}

}

Still no luck :(

FRR
  • 10,772
  • 13
  • 43
  • 80
  • Oh, I had same problem before. Maybe this answer may help you. http://stackoverflow.com/questions/19834842/android-gallery-on-kitkat-returns-different-uri-for-intent-action-get-content I hope for your good luck. – Konifar Oct 06 '15 at 23:40

2 Answers2

2

@CommonsWare's asnwer must be the right way of solving this, but I'm not sure how to implement his solution. I've ended up doing what @Paul Burke recomends on this link:

Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT

EDIT

For my particular case, this is how my code ended up. I leave this here for future reference. (I'm using @CommonsWare's explanation) see his answer above.

               try {
                    InputStream inputStream = getContentResolver().openInputStream(uri);
                    BufferedReader br = null;
                    if (inputStream != null) {
                        br = new BufferedReader(new InputStreamReader(inputStream));

                        String line;
                        while ((line = br.readLine()) != null) {
                            text.append(line);
                            text.append("\n");
                        }
                    } else {
                        subscriber.onError(new InputException("There's something seriously wrong with this file"));
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                    subscriber.onError(e);
                }
Community
  • 1
  • 1
FRR
  • 10,772
  • 13
  • 43
  • 80
1

I tried to use a content resolver to get the file path from the URI like this

There is no file path. A Uri does not necessarily point to a file that you can access on your local filesystem, just as the URL to this Web page does not necessarily point to a file that you can access on your local filesystem. The Uri might:

  • represent a file held in internal storage of the other app
  • represent a BLOB column value in a database
  • represent a file held in "the cloud", to be downloaded when requested
  • etc.

Use a ContentResolver and methods like openInputStream() to read in the content represented by the Uri, just like you would use HttpUrlConnection to read in the content represented by the URL for this Web page. openInputStream() takes the Uri as a parameter and returns an InputStream. You would use that InputStream the same way you would any other InputStream (e.g., FileInputStream, InputStream from HttpUrlConnection). The exact mechanics of that will depend a lot on the underlying data (e.g., read in a string, pass to BitmapFactory to decode a Bitmap).

Community
  • 1
  • 1
CommonsWare
  • 910,778
  • 176
  • 2,215
  • 2,253
  • Yup, I've seen your comments on other stackoverflow posts and fixed my code, check out the "edited" part of my question – FRR Oct 06 '15 at 23:52
  • @feresr: The edited part of your question is your problem. Get rid of `getRealPathFromURI()`. Use `ContentResolver` and `openInputStream()` to read in the content represented by the `Uri`. – CommonsWare Oct 06 '15 at 23:58
  • oh, thanks. let me try that, I'll get back to you :) – FRR Oct 07 '15 at 00:02
  • "Or, perhaps do the inverse: try to open a stream on the Uri, and if that fails, then see if the _DATA pattern is in play." Do you happen to have an example on how to do this? (open a stream on the Uri) – FRR Oct 07 '15 at 00:49
  • @feresr: "open a stream on the Uri" -- as I wrote twice previously, and will now put in boldface to perhaps help with readability, **use a `ContentResolver` and `openInputStream()` to read in the content represented by the `Uri`**. You know how to get a `ContentResolver`, as that is in your code in your question. `openInputStream()` takes one parameter: the `Uri` to open. You get an `InputStream` back, just as you get an `InputStream` to read in data from a Web server via `HttpUrlConnection`, or you get an `InputStream` to read in data from a local file via `FileInputStream`. – CommonsWare Oct 07 '15 at 11:04
  • I carefully read your comment and I knew what you meant, I just didn't know HOW to go about doing so. I've updated your answer with the code to read from the inputstream, if you think it's OK, please leave a comment so I can mark this answer as the accepted one. Thanks!. – FRR Oct 07 '15 at 12:41
  • @feresr: I added more clarity, including a link to a popular SO question on reading in text from an `InputStream`. – CommonsWare Oct 07 '15 at 13:04