我有一个小部件,我试图用它来显示我的应用程序的本地数据库里面的列表视图中的信息。
我正在使用RemoteViewsService.RemoteViewsFactory接口来加载我的列表内容。如果我运行在onDataSetChanged方法中重新加载列表的代码块。应用程序崩溃时显示以下消息:
11-01 16:40:39.540: E/ACRA(27175): DataDisplay fatal error : Permission Denial: reading com.datadisplay.content.ContentProviderAdapter uri content://com.datadisplay.provider.internalDB/events from pid=573, uid=10029 requires the provider be exported, or grantUriPermission()
但是,在类的构造函数中运行的相同代码工作得很好。当然,我需要在onDataSetChanged方法中使用它来进行更新和填充。
这是我的提供者在清单中的条目:
<provider android:name="com.datadisplay.content.ContentProviderAdapter"
android:authorities="com.datadisplay.provider.internalDB"
android:exported="true"
android:enabled="true"
android:grantUriPermissions="true">
<grant-uri-permission android:pathPattern="/events/"/>
</provider>
我正在导出它并授予Uri权限,如错误消息请求,但它仍然失败。我发现了这个问题,这个人有问题,但最终删除了他的自定义权限,并且它有效。我没有这样的自定义权限,但仍然没有运气:
Widget with content provider; impossible to use ReadPermission?
如果有人有洞察力,我会非常感激,这令人非常沮丧,哈哈。
答案 0 :(得分:29)
这种情况正在发生,因为正在从远程进程调用RemoteViewsFactory,并且该上下文正用于权限实施。 (远程调用者没有使用您的提供者的权限,因此它会抛出SecurityException。)
要解决此问题,您可以清除远程进程的标识,以便针对您的应用而不是针对远程调用方检查权限强制执行。以下是您在整个平台上可以找到的常见模式:
final long token = Binder.clearCallingIdentity();
try {
[perform your query, etc]
} finally {
Binder.restoreCallingIdentity(token);
}
答案 1 :(得分:9)
将其放入onDataSetChanged()
方法:
Thread thread = new Thread() {
public void run() {
query();
}
};
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
}
从query()
方法中的数据库中获取数据。我不知道为什么在单独的线程中获取数据有助于解决这个问题,但它的工作原理!我从一个Android示例中得到了这个。
答案 2 :(得分:9)
如果这只发生在4.2而不是其余部分,则需要设置android:exported =“true”,因为默认值已更改: http://developer.android.com/about/versions/android-4.2.html
默认情况下不再导出内容提供商。也就是说,android:exported属性的默认值现在是“false”。如果其他应用程序能够访问您的内容提供者很重要,那么您现在必须明确设置android:exported =“true”。