android - Android Content Provider 权限定义是否违反了 DRY 规则?

标签 android android-contentprovider dry

Android 的内容提供程序 must have :

At least one authority must be specified.

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

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

然后,要实现此 CP,需要在 CP 内定义相同的字符串,如 android-BasicSyncAdapter FeedProvider.java 中所示。 CONTENT_AUTHORITY

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

由于我们必须两次定义这个字符串,这是否基本上违反了 DRY 规则 - 如果我在一个地方更改它,我必须记住在其他地方也更改它。

最佳答案

其实你不必多次指定权限。在我们的OpenTasks Provider我们在运行时从 list 加载权限。

基本思想是这样的:

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 尚不存在。

您可以选择在字符串资源中指定权限,然后从 list 中引用它,如下所示:

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

在您的内容提供程序中,您照常加载权限:

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

如果您的内容提供商为多个机构提供服务,那就会有点困难,但这可能不是一个好主意。

更新以跟进您的评论:

我认为向合约提供上下文没有问题。

而不是写类似的东西

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 作为库导入到具有不同权限的不同项目中,并且不需要更改一行代码。

顺便说一句,我更喜欢第一个版本(从 list 加载权限),因为在这种情况下你甚至不需要字符串资源。您只需 inject ${applicationId}并且永远不要再碰它。

以下 list fragment 可保证您的权限对于导入该权限的每个应用程序都是唯一的:

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

关于android - Android Content Provider 权限定义是否违反了 DRY 规则?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36713033/

相关文章:

android - 如何访问不同 Activity 中 fragment 的 contentResolver?

c# - 将库重构为异步,如何避免重蹈覆辙?

Ruby 备份 gem - 共享配置?

android - 如果我更改 SharedPreference 的首选项设置,会发生什么情况

android - 获取 SQLite 数据库的下一个 AUTO_INCREMENT 值

android - 选择为 textView 和 editText 添加边框形状时,

android - 从 ContentProvider 中删除?

android - 从 contentProvider.update() 更改 uri 的 notifyChange

javascript - 我想从 javascript(或 html,就此而言)访问多分辨率 .ico 中的某些分辨率文件

android - Android 的 Http 库比较。哪个是首选?