2016-05-14 6 views
2

私は2つのコンテンツプロバイダベースのアプリケーションAとBを持っています。どちらも独自のコンテンツプロバイダを持ち、AとBからデータを読み取るように設定されています。他のアプリがバックグラウンドのときはすべて正常に動作します。しかし、アプリが殺されたか、バックグラウンドで存在しない場合、別のコンテンツプロバイダを見つけることができませんでした。たとえば、App BはApp Aからデータを読み取ろうとしていますが、 'A'がバックグラウンドで実行されているときに 'B'は 'A'からデータを正常に読み取ることができますが、 'A'が実行されていないと致命的なエラーバックグラウンドでカスタムコンテンツプロバイダからのデータへのアクセス

どのような考えですか?

[編集] this postと同じ問題が発生しています。 私は両方のアプリのマニフェストでこれをしました:

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

この私が取得していますエラー:サポートされていないURI(クエリ): java.lang.IllegalArgumentExceptionがを区分けするために、例外を書く

コンテンツを://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.ContentPro vider $ Transport.query android.os.Binder.execTransact(Binder.java:461)でandroid.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)で(ContentProvider.java:218)

注:これは、別のアプリがバックグラウンドにない場合にのみ発生します。そうでない場合は、期待通りに機能します(お互いのデータをうまく読み込めます)。ここで

[EDIT 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が一致しません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()方法でswitchIllegalArgumentExceptionをスローバックdefault魔女に落ちます。

init()onCreate()にコールするか、またはスタティックイニシャライザでUriMatcherを完全に初期化する必要があります。

+0

UriMatcherを動的に初期化したい(Urisを追加する)。コンテンツプロバイダがマニフェストから権限を読み取ることは可能ですか? – 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.appA-provider

ある

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

としてマニフェストに当局が定義されている、しかしどちらかcom.example.providerまたはcom.example.provider.myprovider

です

関連する問題