The solution phreed gives in the bottom half of question is basically correct. I'll try to add some more details here.
When you do getContentResolver().openInputStream(...)
, content resolver will go to your content provider and call its openFile
method. This is how the openFile
looks in ContentProvider.java:
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
throw new FileNotFoundException("No files supported by provider at "
+ uri);
}
So this explains where the "No files supported ..." error exactly comes from! You get around this by overriding openFile
method in your subclass and providing your own implementation. It's neat: you get perfect control of where your files get placed when any client does openInputStream
or openOutputStream
.
Code sample in phreed's question gives a hint how the implementation could look like. Here's my slightly modified version which also creates directories and files as needed. I'm novice at this stuff so this might not be the optimal way of doing things, but it gives an idea. For one thing, it should probably check if external storage is available.
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File root = new File(Environment.getExternalStorageDirectory(),
"/Android/data/com.example.myapp/cache");
root.mkdirs();
File path = new File(root, uri.getEncodedPath());
// So, if the uri was content://com.example.myapp/some/data.xml,
// we'll end up accessing /Android/data/com.example.myapp/cache/some/data.xml
int imode = 0;
if (mode.contains("w")) {
imode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
if (!path.exists()) {
try {
path.createNewFile();
} catch (IOException e) {
// TODO decide what to do about it, whom to notify...
e.printStackTrace();
}
}
}
if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY;
if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND;
return ParcelFileDescriptor.open(path, imode);
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…