Can't ACTION_VIEW a file on external storage

2019-07-21 07:26发布

I have a file in my Android phone's external storage (emulated, in this case). Knowing the path to it and / or having a File object representing it, how can I use an Intent to open it in the appropriate app?

The first thing I tried was:

startActivity(new Intent(Intent.ACTION_VIEW, Uri.fromFile(file)));

I'm sure this was working at one point, because I tested it and moved on to another part of the app. Now it always throws ActivityNotFoundException. The file definitely exists because file.exists() returns true and I know it's the right file, but no apps volunteer to open it.

The only type of file I can still open this way is .pdf, for which Adobe Reader is selected, despite not being the only PDF reader installed on my device and not having been set default. I've noticed that Adobe Reader also offers to open pdf files which are located online (it appears as an alternative to downloading the pdf with Chrome). This suggests to me that only Adobe Reader is being found as a match for the Intent because the location is thought to be remote (though not online, because Chrome and other file downloading apps aren't listed as alternatives).

I've also tried explicitly stating the MIME type:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/msword");
startActivity(intent);

This causes the Intent to be matched to the right apps, however they all fail to actually open the file. I've tested this both with hardcoded strings for the MIME types and by using MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension), passing the file extension. For a variety of file types, the correct apps were suggested but they all failed to open the file.

EDIT:

Setting the MIME type explicitly would have worked, but I made a very stupid mistake, which I should probably explain in an answer.

The files I've tried to open are from the internet, downloaded in my app with the aid of DownloadManager. I use its feature to display a notification when one finishes downloading. Clicking one of these notifications opens the file perfectly. I've tried to find the source code for the Intent fired when a DownloadManager finished notification is clicked, but had no luck.

Also, apps such as ES File Explorer can navigate to where my files are downloaded to and open them with no problem. What am I doing wrong?

Is it simply that it's no longer possible to ACTION_VIEW a file on the external storage? My app also downloads files to the internal storage temporarily, and these can still be opened with no issues like so:

//This works for files on internal storage:
Uri uri = FileProvider.getUriForFile(context, AUTHORITY, file);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

And as for it working in the past, could updating Eclipse, the SDK Tools plugin and the Android SDK itself have stopped my original solution from working?

1条回答
走好不送
2楼-- · 2019-07-21 08:00

When I tried setDataAndType, out of laziness I must have left:

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.fromFile(file));

and just added another line to make:

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.fromFile(file));
intent.setType(theMimeType);

...assuming that it would be the same as:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), theMimeType);

I must have then forgotten that I hadn't actually tried setDataAndType and gone on to write this question. Using setType on its own seemed to remove the Uri I'd passed as an argument to the constructor. Using LogCat to view the logged details of the intents, I saw that leaving the MIME type to be inferred resulted in no type, using setType after already setting a Uri resulted in no Uri being specified for some reason, and using setDataAndType meant they were both specified, causing the Intent to work properly.

So what I was doing wrong was setting the type and data separately, instead of using setDataAndType.

查看更多
登录 后发表回答