Android 安卓内容提供商权限定义是否违反了干式规则?

Android 安卓内容提供商权限定义是否违反了干式规则?,android,android-contentprovider,dry,Android,Android Contentprovider,Dry,Android的内容提供商: 必须至少指定一个权限 例如,在谷歌的样本中 因为我们必须两次定义这个字符串,这不是基本上打破了枯燥的规则吗?如果我在一个地方更改它,我也必须记住在其他地方更改它。实际上,您不必多次指定权限。在我们的示例中,我们在运行时从清单加载权限 其基本思想是: Context context = getContext(); PackageManager packageManager = context.getPackageManager(); ProviderInfo prov

Android的
内容提供商

必须至少指定一个权限

例如,在谷歌的样本中


因为我们必须两次定义这个字符串,这不是基本上打破了枯燥的规则吗?如果我在一个地方更改它,我也必须记住在其他地方更改它。

实际上,您不必多次指定权限。在我们的示例中,我们在运行时从清单加载权限

其基本思想是:

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
尚未出现

或者,您可以在字符串资源中指定权限,并从清单中引用它,如下所示:

<provider
    android:name=".provider.FeedProvider"
    android:authorities="@string/authority"
    android:exported="false" />
如果你的内容提供商服务于多个权威机构,这会有点困难,但这可能不是一个好主意

更新以跟进您的评论: 我认为为合同提供
上下文没有问题

而不是写这样的东西

Cursor c = contentProvider.query(MyContract.Items.CONTENT_URI,
    null, null, null, null);
你就写吧

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

没有太大区别,只是当您还需要添加ID时,它会更加方便:

Cursor c = contentProvider.query(MyContract.Items.itemUri(getContext(), myItemId),
    null, null, null, null);
上下文
传递给这些静态方法通常不是问题,因为您无论如何都需要上下文来获取
ContentResolver

这种技术的一个优点是,您的代码完全独立于实际权限,您可以轻松地将
ContentProvider
作为库导入到具有不同权限的不同项目中,并且不需要更改代码的任何一行

顺便说一句,我更喜欢第一个版本(从清单加载权限),因为在这种情况下,您甚至不需要字符串资源。你可以再也不要碰它了

以下清单代码段保证您的权限对于您导入的每个应用程序都是唯一的:

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


hmmm,我希望我有你的问题…;-)字符串资源解决方案有一个问题-您必须在扩展内容提供程序的类中使用getContext()-这很容易,但如果您必须在例如Contract类中知道此权限值,那么您将使其依赖于上下文,这是weakUpdated我的答案,以详细说明您所关心的问题。看起来不错,我会试试看——但为什么契约是一个接口——有什么好的理由吗?你可以把它变成一个类。没有具体原因。我只是认为它更合适,因为契约基本上是某种其他形式的接口(即使您从未将其实例化)。
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();
       }
}
Cursor c = contentProvider.query(MyContract.Items.itemUri(getContext(), myItemId),
    null, null, null, null);
<provider
    android:name=".provider.FeedProvider"
    android:authorities="${applicationId}.myauthority"
    android:exported="false" />