Accessing data from Custom Content Providers

余生颓废 提交于 2019-12-11 00:59:07

问题


I've two content provider based apps A and B. Both have their own content providers and are setup for reading data from A and B and vice versa. Everything works fine when the other app is in background. But couldn't find another content provider if the app is killed or not present in background. For example, App B wants to read data from App A. 'B' can read data from 'A' successfully when 'A' is running in background, but gave fatal error (Match uri not found) if 'A' is not running in background.

Any thoughts ?

[EDIT] I'm getting the same issue as this post. I've this in both apps' manifest:

   <provider
        android:name="MyContentProvider"
        android:authorities="com.example.${applicationId}-provider"
        android:enabled="true"
        android:exported="true"
        android:grantUriPermissions="true">
    </provider>

This the error I'm getting:

Writing exception to parcel java.lang.IllegalArgumentException: Unsupported URI(Query): content://com.example.appA-provider/appA at com.example.provider.MyContentProvider.query(MyContentProvider.java:142) at android.content.ContentProvider.query(ContentProvider.java:1007) at android.content.ContentProvider$Transport.query(ContentProvider.java:218) at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112) at android.os.Binder.execTransact(Binder.java:461)

Note: This only happens when another app is not in background, otherwise it works as expected (can read each other's data fine).

[EDIT 2] Here's code for MyContentProvider:

package com.example.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;


public class MyContentProvider extends ContentProvider {

    private static DatabaseHelper dbHelper;

    private static final int ALL_ENTRIES = 1;
    private static final int SINGLE_ENTRY = 2;

    private String mAuthority = BuildConfig.APPLICATION_ID;
    private static UriMatcher uriMatcher;

    public Uri CONTENT_URI= null;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    }

    public MyContentProvider() {}

    public void init(String packageName, String authority) {
        if (authority == null) {
            setAuthority(packageName, true);
        } else {
            setAuthority(authority, false);
        }

        uriMatcher.addURI(getAuthority(), TABLE_NAME, ALL_ENTRIES);
        uriMatcher.addURI(getAuthority(), TABLE_NAME + "/#", SINGLE_ENTRY);
        CONTENT_URI =
                Uri.parse("content://" + getAuthority() + "/" + TABLE_NAME);
    }

    private void setAuthority(String packageName, boolean isPackageName) {
        if (isPackageName) {
            mAuthority = packageName + ".myprovider";
        } else {
            mAuthority = packageName;
        }
    }

    public String getAuthority() {
        return mAuthority;
    }

    public Uri getContentUri() {
        return CONTENT_URI;
    }

    @Override
    public boolean onCreate() {
        dbHelper = new DatabaseHelper(getContext());
        return false;
    }

    //Return the MIME type corresponding to a content URI
    @Override
    public String getType(Uri uri) {

        if (uri == null) {
            throw new IllegalArgumentException("Content uri is null: " + uri);
        }
        if (uriMatcher == null) {
            throw new IllegalArgumentException("Unsupported Match URI: " + uri);
        }

        switch (uriMatcher.match(uri)) {
            case ALL_ENTRIES:
                return "vnd.android.cursor.dir/vnd." + getAuthority() + "." + TABLE_NAME;
            case SINGLE_ENTRY:
                return "vnd.android.cursor.item/vnd." + getAuthority() + "." + TABLE_NAME;
            default:
                throw new IllegalArgumentException("Unsupported URI: " + uri);
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri _uri = null;
        long id = 0;
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        switch (uriMatcher.match(uri)) {
            case ALL_ENTRIES:
            case SINGLE_ENTRY:
                id = db.insert(TABLE_NAME, null, values);
                getContext().getContentResolver().notifyChange(uri, null);
                _uri = Uri.parse(CONTENT_URI + "/" + id);
                break;
            default:
                throw new IllegalArgumentException("Unsupported URI (insert): " + uri);
        }

        return _uri;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {

        SQLiteDatabase db = dbHelper.getWritableDatabase();
        SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();

        Cursor cursor = null;
        String id = null;

        switch (uriMatcher.match(uri)) {
            case ALL_ENTRIES:
                queryBuilder.setTables(TABLE_NAME);
                cursor = queryBuilder.query(db, projection, selection,
                        selectionArgs, null, null, sortOrder);
                break;
            case SINGLE_ENTRY:
                queryBuilder.setTables(TABLE_NAME);
                id = uri.getPathSegments().get(1);
                if (id != null && !id.isEmpty()) {
                    queryBuilder.appendWhere(TABLE_NAME + "=" + id);
                }

                cursor = queryBuilder.query(db, projection, selection,
                        selectionArgs, null, null, sortOrder);
                break;
            default:
                throw new IllegalArgumentException("Unsupported URI(Query): " + uri);
        }

        return cursor;
    }
}

回答1:


You can not initialize the content provider from somewhere else in your code like this, as the ContentProvider might be the first (or only) component of your app that's instantiated.

However, you can read the authority dynamically from the Manifest or a String resource. In my answer on Does Android Content Provider authority definition break the DRY rule? I outlined how we that in our OpenTasks-Provider.




回答2:


I don't see a call to init() in content provider. Is it only called from elsewhere as part of the application's start ?

If so that may explains why the content provider fails when the application is not already started : In this case the UriMatcher is empty and the switch in the query() method falls back to default witch throws the IllegalArgumentException.

You should either call init() in onCreate() or fully initialize the UriMatcher in the static initializer.




回答3:


You are setting the authority as

private void setAuthority(String packageName, boolean isPackageName) {
        if (isPackageName) {
            mAuthority = packageName + ".myprovider";
        } else {
            mAuthority = packageName;
        }
    }

So your mAuthority is either com.example.provider or com.example.provider.myprovider

However, you have defined authorities in the manifest as

android:authorities="com.example.${applicationId}-provider"

that is com.example.appA-provider



来源:https://stackoverflow.com/questions/37223456/accessing-data-from-custom-content-providers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!