簡體   English   中英

Android Content Provider 權限定義是否違反了 DRY 規則?

[英]Does Android Content Provider authority definition break the DRY rule?

Android 的Content Provider 必須具有

必須至少指定一個權限。

因此,例如在 Google 的示例android-BasicSyncAdapter AndroidManifest.xml 中

<provider
    android:name=".provider.FeedProvider"
    android:authorities="com.example.android.basicsyncadapter"
    android:exported="false" />

然后要實現這個 CP,需要像在android-BasicSyncAdapter FeedProvider.java CONTENT_AUTHORITY一樣在 CP 中定義相同的 String

public static final String CONTENT_AUTHORITY = "com.example.android.basicsyncadapter";

由於我們必須兩次定義這個字符串,這是否基本上違反了 DRY 規則 - 如果我在一個地方更改它,我必須記住也要在其他地方更改它。

實際上,您不必多次指定權限。 在我們的OpenTasks Provider 中,我們在運行時從清單加載權限。

基本思想是這樣的:

Context context = getContext();
PackageManager packageManager = context.getPackageManager();
ProviderInfo providerInfo = packageManager.getProviderInfo(
    new ComponentName(context, this.getClass()),
    PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA);
String authority = providerInfo.authority;

在 Android 2.2 上,您必須付出一些額外的努力,因為getProviderInfo方法尚不存在。

或者,您可以只在 String 資源中指定權限並從 Manifest 中引用它,如下所示:

<provider
    android:name=".provider.FeedProvider"
    android:authorities="@string/authority"
    android:exported="false" />

在您的內容提供商中,您可以像往常一樣加載權限:

String authority = getContext().getString(R.string.authority);

如果您的內容提供商為多個權威機構提供服務,這會有點困難,但這無論如何都不是一個好主意。

更新以跟進您的評論:

我認為為合同提供Context沒有問題。

而不是寫類似的東西

Cursor c = contentProvider.query(MyContract.Items.CONTENT_URI,
    null, null, null, null);

你只會寫

Cursor c = contentProvider.query(MyContract.Items.itemsUri(getContext()),
    null, null, null, null);

public final interface MyContract {

    // ... lots of other tables ...

    public final static class Items {
       public final static String CONTENT_PATH = "items";

       // all the contract definitions

       public final static Uri itemsUri(Context context) {
           return new Uri.Builder()
               .scheme("content")
               .authority(context.getString(R.string.authority)).
               .path(CONTENT_PATH)
               .build();
       }
}

沒有太大的區別,只是當你還需要添加一個 ID 時會更加方便:

Cursor c = contentProvider.query(MyContract.Items.itemUri(getContext(), myItemId),
    null, null, null, null);

Context傳遞給這些靜態方法通常不是問題,因為無論如何您都需要 Context 來獲取ContentResolver

這種技術的一個優點是您的代碼完全獨立於實際權限,您可以輕松地將ContentProvider作為庫導入到具有不同權限的不同項目中,並且您無需更改任何一行代碼。

順便說一句,我更喜歡第一個版本(從清單加載權限),因為在這種情況下您甚至不需要 String 資源。 你可以只注入${applicationId}並且永遠不要再碰它。

以下清單代碼段保證您的權限對於您導入它的每個應用程序是唯一的:

<provider
    android:name=".provider.FeedProvider"
    android:authorities="${applicationId}.myauthority"
    android:exported="false" />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM