问题描述
我有两个基于内容提供商的应用程序A和B.它们都有自己的内容提供商,并且设置为从A和B读取数据,反之亦然.当其他应用程序在后台运行时,一切正常.但是,如果该应用被杀死或在后台不存在,则找不到其他内容提供商.例如,应用程序B要从应用程序A中读取数据.当"A"在后台运行时,"B"可以从"A"中成功读取数据,但是如果没有运行"A",则会出现致命错误(找不到匹配uri).在后台.
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.
有什么想法吗?
我遇到与此帖子相同的问题.我在两个应用的清单中都有此提示:
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>
这是我得到的错误:
注意:仅当另一个应用程序不在后台运行时,才会发生这种情况,否则它将按预期运行(可以很好地读取彼此的数据).
Note: This only happens when another app is not in background, otherwise it works as expected (can read each other's data fine).
这是MyContentProvider的代码:
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;
}
}
推荐答案
您不能像这样在代码中的其他地方初始化内容提供程序,因为ContentProvider可能是您实例化的应用程序的第一个(或唯一)组件
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.
但是,您可以从清单或String资源动态读取权限.在我关于的答案中权限定义违反了DRY规则?我概述了我们如何在OpenTasks-Provider中做到这一点.
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.
这篇关于从自定义内容提供者访问数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!