2016-05-14 103 views
2

我有两个内容提供商的基于应用程序A和B都拥有自己的内容提供商,并设置为从A和B读取数据,反之亦然。当其他应用程序处于后台时,一切正常。但是,如果应用程序在后台被杀害或不存在,则无法找到另一个内容提供者。例如,应用程序B想要从应用程序A读取数据。如果'A'在后台运行,'B'可以成功读取'A'的数据,但如果'A'未运行,则发生致命错误(找不到匹配uri)在背景中。从自定义内容提供商访问数据

有什么想法?

[编辑] 我得到了相同的问题this post。 我在这两个应用程序清单已经这样:

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

这我得到的错误:

写例外包裹 java.lang.IllegalArgumentException异常:不支持的URI(查询):内容://com.example.appA-provider/appA at android.content.example.provider.MyContentProvider.query(MyContentProvider.java:142) at android.content.ContentProvider.query(ContentProvider.java:1007) at android。 content.ContentPro vider $ Transport.query(ContentProvider.java:218) 在android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112) 在android.os.Binder.execTransact(Binder.java:461)

注意:这只发生在另一个应用程序不在后台时,否则它按预期工作(可以很好地读取彼此的数据)。

[编辑2] 这里的代码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; 
    } 
} 
+0

'匹配uri not foun d'没有说什么,发布你的代码和完整的堆栈跟踪 – pskink

+0

检查两个清单标签并考虑将内容提供者代码放入库中? – Pomagranite

+0

@Pomagranite:我已经把代码放在上面了。是的,我使用内容提供商代码作为库。 – bianca

回答

0

不能初始化从别的地方内容提供商在你的代码是这样,因为ContentProvider的可能是被实例您的应用程序的第一个(或唯一)的组成部分。

但是,您可以从清单或字符串资源动态读取的权限。在我对Does Android Content Provider authority definition break the DRY rule?的回答中,我概述了我们在OpenTasks-Provider中的情况。

+0

我正在尝试为内容提供者使用库。我期望调用init()应该初始化使用内容提供程序库来创建它自己的cp的应用程序。 Offcourse它不工作。有没有可能把cp封装成一个库。如何动态初始化? – bianca

+0

当然,您可以在库中提供ContentProvider。这就是我们用TaskProvider所做的(目前我们将它作为jar发布,但我们计划切换到aar。请看我们如何“自动初始化”我们的[TaskProvider](https://github.com) /dmfs/opentasks-provider/blob/master/src/org/dmfs/provider/tasks/TaskProvider.java#L159) – Marten

0

我没有看到在内容提供商init()通话。它是否仅从其他地方被调用作为应用程序开始的一部分?

如果是这样,可能解释了为什么当应用程序尚未启动,内容提供商失败:在这种情况下,UriMatcher是空的,在query()方法switch回落到default女巫投IllegalArgumentException

您应该在onCreate()中调用init()或在静态初始化程序中完全初始化UriMatcher

+0

我想动态初始化(添加Uris)UriMatcher。内容提供者是否有可能根据Manifest来阅读其权限? – bianca

+0

'getContext()'可用于'onCreate()'(不在构造函数中)。上下文让您可以访问大量信息。在你的情况下,不'getPackageManager()','getPackageName()',...提供你所需要的? – bwt

0

要设置权限为

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

所以你mAuthority或者是com.example.providercom.example.provider.myprovider

但是,你已经在清单中定义当局

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

com.example.appA-provider