2016-05-14 104 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