Consuming Content? Be Flexible!
Many times, when we work with a
Uri, we get an
read in the content, and we’re good to go.
Sometimes, though, consumers of content make some unfortunate assumptions.
One assumption is that you can pass
rw in for the mode on
and kin. First, this assumes that you have write access, which may or
may not be true. Plus,
rw requires that the content that you are
working with be stored as a plain file on the filesystem somewhere.
Another related assumption is that the
InputStream is seekable,
reset(). Once again, this only works
if the content in question is backed by a plain file on the filesystem.
However, increasingly, that will not be the case, as more and more
developers turn to publishing content, to get around things like
Uri ban in Android 7.0.
While content may be backed by a plain file on the filesystem,
it might also be backed by:
A file, but one that needs to be transformed on the fly by the provider (e.g., decrypted)
A piece of a file (e.g., an asset packaged in the app’s APK)
Something in memory (e.g., the contents of a
BLOBcolumn that was read in from a database)
Something being streamed from the Internet (though this is kinda risky IMHO, on the provider’s part)
ContentProvider publishing this content will be using something
other than a file-based
ParcelFileDescriptor, usually in the form
of a pipe or socket pair. Those do not support
rw mode, nor do they
In particular, if your app is usable with read-only non-seekable content,
but perhaps with a subset of functionality, make sure that you support
it. For example, a couple of Android PDF viewers — including Google’s
Drive PDF Viewer — seem to require
rw access and crash in situations
where other apps (e.g., Adobe Reader) work fine. Gracefully degrade in
these cases: try for
rw access, and then try for
r access if the
If seekability is the issue, more so than
rw access, you can try
getStatSize() on the
ParcelFileDescriptor that you get
openFileDescriptor() on the
ContentResolver. If this
returns -1, then there is a good chance that the stream is not file-backed
and will not support seeking. If this returns 0 or a positive value,
that should be the size of the file that the stream is delivering to you.
If you need a test case for these cases, toss
in your test suite and test against an asset served via a
Uri. This will be a non-seekable stream on which
rw is not an
option (as you cannot modify an asset).
The majority of the time, when you get a
Uri, it will
be served by a provider that is using a file for the content. In that
rw mode may be available, and seeking should work. Just do
not assume that you can always do that for every
sure that you test cases where the
Uri is something else, and that
you handle those cases as best as you can.
Need Android app development training for your team? Mark Murphy has trained hundreds! Learn more!