2

I want to save/load binary data with my ContentProvider. For saving I wrote this code:

        long id = database.insert(TABLE_NAME, null, values);

        Uri uri = ContentUris.withAppendedId(
                LocationContentProvider.CONTENT_URI, id);

        OutputStream outStream;
        try {
            Bitmap bmp = ...

            if (bmp != null) {
                outStream = cr.openOutputStream(uri);
                ImageUtils.saveToStream(bmp, outStream,
                        Bitmap.CompressFormat.PNG);
                outStream.close();
                bmp.recycle();
            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.d(TAG, "Could not save logo to " + uri.toString());
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "Could not save logo to " + uri.toString());
        }

But of course, initially the file does not exist. So I get the FileNotFoundException. My question is, how do I force the ContentProvider to create the file if not yet existent? And do I need to implement ContentProvider.openFile?

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
        throws FileNotFoundException {
    // TODO Auto-generated method stub
    return super.openFile(uri, mode);
}
Matthias
  • 5,574
  • 8
  • 61
  • 121

1 Answers1

0

I finally figured out that you have to override ContentProvider.openFile. See this post for more details. My method within the ContentProvider looks like this:

public ParcelFileDescriptor openFile(Uri uri, String mode)
        throws FileNotFoundException {

    ContextWrapper cw = new ContextWrapper(getContext());

    // path to /data/data/yourapp/app_data/dir
    File directory = cw.getDir(BASE_PATH, Context.MODE_WORLD_WRITEABLE);
    directory.mkdirs();

    long id = ContentUris.parseId(uri);
    File path = new File(directory, String.valueOf(id));

    int imode = 0;
    if (mode.contains("w")) {
        imode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
        if (!path.exists()) {
            try {
                path.createNewFile();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    if (mode.contains("r"))
        imode |= ParcelFileDescriptor.MODE_READ_ONLY;
    if (mode.contains("+"))
        imode |= ParcelFileDescriptor.MODE_APPEND;

    return ParcelFileDescriptor.open(path, imode);
}
Community
  • 1
  • 1
Matthias
  • 5,574
  • 8
  • 61
  • 121
  • So do you need to call this method or it gets called by the system when you do cr.openOutputStream(uri)? – Viktoriia Chebotar Jul 31 '19 at 21:46
  • You need to bind the content provider to UI element. Once the UI is loading specific content. Once you’re requested to bind the data of a single content to the UI (for instance a row in a ListView) then you would need to use your content provider to load the data as explained here. Hope it helps. https://www.grokkingandroid.com/handling-binary-data-with-contentproviders/ – Matthias Jul 31 '19 at 22:53