How to store large blobs in an android content provider?
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);
}
Passing binary blob through a content provider
You won't be able to use a MatrixCursor
to send the byte array. This is because it depends on AbstractCursor#fillWindow
method which fills the CursorWindow
using Object#toString
. So what is happening is that the byte array toString
method is being called and it's storing that instead of the contents of the byte array which is what you want. The only way around this I can see is to implement your own Cursor that will fill the CursorWindow
appropriately for a byte array.
Storing file in Android Database (Custom Content Provider) using _data field - v1.6
To see where "No files supported by provider at..." comes from, have a look here. The situation there seems very similar with the one you've described.
In short, your content provider (or some of its superclasses) needs to override and implement openFile
method. That error is raised by the default "not implemented--back off!" code in ContentProvider.java
.
I find it helpful to peek at underlying source code of the framework when I get stuck, since documentation is sometimes a bit lacking.
How to pass binary data between two apps using Content Provider?
Why not giving the data as Base64 string?
Content provider file storage No Such file or directory
I had a similar problem to this. In your emulator, if the folder corresponding to Environment.getDataDirectory()
does not exist then you will get an exception. You need to manually create the folder first (not by the code) through either the terminal or adb. Once you do that, try running your code again and it should work.
Content Provider commons
Should we use Content Provider, when data are not meant to be shared across applications?
Content Provider is one of the good features to share data among applications or activities within applications.
If you want to use content provider for your application and don't want to share then you can use content provider and it is really nice abstraction if you use content provider.
When having multiple data tables connected together, should we create single Provider for
every data type, or can we use single provider for all of them?
For different tables I think you have to create different content provider.In Android there are different content provider for different tables and database.So better you create
separate content provider for all the tables.
Related Topics
Android - How to Intercept the 'Install Application' Intent
React-Native :Java.Lang.Unsatisfiedlinkerror: Couldn't Find Dso to Load: Libhermes.So
Android: Total Height of Scrollview
Findfragmentbytag() Returns Null After Perform a Fragmenttransaction Using Replace() Method
How to Use Data Binding and Kotlin in Android Studio 3.0.0
Developing Two Android Apps and Communicating Between Two
Android: How to Enable/Disable an Activity's Intent Filter Programmatically
Deep Linking Not Working in Chrome
Status Bar Turns White and Does Not Show Content Behind It
Android Webview Anchor Link (Jump Link) Not Working
Create a Chat Bubble in Android
Firebase: When Ondisconnect Event Fire
Android Imageview's Onclicklistener Does Not Work
Rendering Problems in Android Studio V 1.1/1.2
Android Sdk Tools Revision 22 Issue