- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
在 android 平台上(在 ICS 上确认),如果内容提供者在客户端处于查询中间时终止(即具有打开的游标),则框架决定终止持有打开游标的客户端进程。
这是我尝试使用下载管理器查询时的 logcat 输出,该查询在执行查询后休眠。 “ sleep ”是为了重现问题。您可以想象当提供者在正确/错误的时间死亡时,它会在常规用例中发生。然后干掉 com.android.media(托管 downloadProvider)。
“正在杀死 com.example (pid 12234),因为提供者 com.android.providers.downloads.DownloadProvider 正处于垂死过程 android.process.media”
我在 ActivityManagerService::removeDyingProviderLocked 中跟踪了代码
10203 private final void removeDyingProviderLocked(ProcessRecord proc,
10204 ContentProviderRecord cpr) {
10205 synchronized (cpr) {
10206 cpr.launchingApp = null;
10207 cpr.notifyAll();
10208 }
10210 mProvidersByClass.remove(cpr.name);
10211 String names[] = cpr.info.authority.split(";");
10212 for (int j = 0; j < names.length; j++) {
10213 mProvidersByName.remove(names[j]);
10214 }
10215
10216 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10217 while (cit.hasNext()) {
10218 ProcessRecord capp = cit.next();
10219 if (!capp.persistent && capp.thread != null
10220 && capp.pid != 0
10221 && capp.pid != MY_PID) {
10222 Slog.i(TAG, "Kill " + capp.processName
10223 + " (pid " + capp.pid + "): provider " + cpr.info.name
10224 + " in dying process " + (proc != null ? proc.processName : "??"));
10225 EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
10226 capp.processName, capp.setAdj, "dying provider "
10227 + cpr.name.toShortString());
10228 Process.killProcessQuiet(capp.pid);
10229 }
10230 }
10231
10232 mLaunchingProviders.remove(cpr);
10233 }
这是政策决定还是提供者死亡后游标访问不安全?
看起来客户端游标正在为 CP 填充的 ashmem 位置保存一个 fd。这就是当服务器(提供者)死机时客户端被杀死而不是像 Binders 那样抛出异常的原因吗?
最佳答案
游标
不安全。虽然我认为大多数时候 Cursor
仅用于对数据的“读取访问”,但它们比这更复杂。
简短的解释在描述Cursor
的Android文档中:
This interface provides random read-write access to the result set returned by a database query.
因此,游标
不仅仅是保存在对象中的数据。它们通过数据库连接在 ResultSet
中保留您的位置。 ResultSet
使用 JDBC 访问数据库。所以 Cursor
仅充当“Java 友好”数据库调用。以下是有关 ResultSet
文档的 Android:
When reading data via the appropriate getter methods, the JDBC driver maps the SQL data retrieved from the database to the Java type implied by the method invoked by the application. The JDBC specification has a table for the mappings from SQL types to Java types.
ResultSet
保持与数据库的连接。数据没有“复制”到接口(interface)中(Cursor
和 ResultSet
都是接口(interface),不是对象;一些实现可能会复制数据,但我没有测试过,因为通过关闭的 Connection
打开 Statement
和 ResultSet
资源可能会导致数据库资源问题)。
Java 为 ResultSet
提供了 JDBC 访问数据库中“结果集表”的接口(interface),如 Java 文档中所述:
A table of data representing a database result set, which is usually generated by executing a statement that queries the database.
http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
您不能向已终止的 ContentProvider 提供“数据库访问”,因为数据库中的 ResultSet
表没有连接,因此应该处理 Cursor
。
编辑:
一条评论表明 Android 不使用 JDBC' 或
ResultSet` - SQLite 的 Android 实现与 JDBC 非常相似,概念在本质上是相同的,只是没有方便的名称和说明。
Android 使用自定义实现这一事实使问题的描述更加困难,尽管我应该在我的原始帖子中提到这一点。如果需要更详细的引用和信息,这里是关于 JDBC 状态和 Android 中 SQLite 接口(interface)实现的 Google Groups 线程:
https://groups.google.com/forum/#!topic/android-developers/zz3qlNL2JDw
从讨论中,您可能会向 Joerg Pleumann 询问更多详细信息......
关于android 内容提供商在提供商崩溃时的稳健性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13922299/
我是一名优秀的程序员,十分优秀!