androidfile-iopermissionsconceptual-model

Trouble Conceptualizing Android File System Access


I want my app to automatically load data from a file at startup & then display a summary of this data for the user. I thought this would be simple, but...

I almost had it working, but found out that it would be tricky putting the data file on the emulated Android provided by Android Studio. So I put a basic version of the file in the package as an asset. My code checked for the file, and if not found, copies the file from assets to the phone storage. So far so good, but then I realized that this didn't really meet the requirements, because the user couldn't customize the file (through another app or by putting a new version of the file on her phone).

I found I needed to use "external" storage (which isn't really external, it's merely shared / public storage). So I used getExternalStoragePublicDirectory() to get access to the Documents folder. In the part of my code which copies the asset file to the Documents folder, I get "java.io.IOException: No such file or directory" when I try to create the target file.

This really threw me for a while, since I had preceded it with mkdirs() to ensure the folder(s) existed and I was trying to create the file in the first place.

After lots of poking around on S/O, it seems my problem may be that I don't have permissions to read / write in the Documents folder. So this is where I can't get my head around how this is supposed to work.

In my Activity's OnCreate(), I want to load the data from my file. But I need to check the permissions first. This is guaranteed to fail the first time, because the user has never granted my app this permission before.

So then I need to request the permission. But this means I can no longer load my data in the OnCreate() method, as I will get the response from the user asynchronously, in a callback method (onRequestPermissionsResult).

If the user says 'No' to my request, I need to make sure the app quits gracefully. If she says 'Yes', then... what? At this point I'm in a callback and my OnCreate() method is no longer running. How can I get back to setting up my Activity?

If I load the data file in the callback method, that only works for the initial case where the user must give permission. But after that, my app (most likely) will not lose permission, so my app will not need to ask for it. The callback will never be executed in this case. So my data file must be loaded... where?

But all of this only happens if the user is running Android 6.0 or higher. If it's an earlier version of Android, then my app can load the data in my Activity's OnCreate() method.

Oh... my head hurts!

How is all of this supposed to work? I don't need a link to the relevant methods. I need a conceptual model - a diagram would really help!


Here's the solution in a diagram: Permissions Conceptual Diagram


Solution

  • How can I get back to setting up my Activity?

    Move the "setting up my Activity" code that depends on file I/O to a separate method. In onCreate(), check to see if you have the permission, and if you do, call that method to set up your activity. If not, call requestPermissions(). In onRequestPermissionsResult(), if you now have the permission, call that method to set up your activity.

    See this sample app, which performs disk I/O from external storage using runtime permissions. The permission-handling logic is isolated in an AbstractPermissionsActivity, leaving the main activity class to handle the real business logic.

    If it's an earlier version of Android, then my app can load the data in my Activity's OnCreate() method.

    Well, you should be doing this disk I/O on a background thread. You can kick off that I/O from onCreate().

    If you are using ContextCompat and ActivityCompat for checking and requesting permissions, respectively, your code will "do the right thing" on older devices, as those classes do the version checks for you.