阅读 759

Android Q(10) ContentObserver 不回调 onChange

App 里有本地相册功能,需要通过 ContentObserver 监听系统数据库变化,从而保证系统相册有数据更新时,App 相册能及时更新,但最近报出某些机型用相机拍照回到 app 后不能刷新相册,最终定位到了是 Android Q 中 ContentObserver 没能收到 onChange 数据导致的

解决办法

    /**
     * Register an observer class that gets callbacks when data identified by a
     * given content URI changes.
     * <p>
     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
     * notifications must be backed by a valid {@link ContentProvider}.
     *
     * @param uri The URI to watch for changes. This can be a specific row URI,
     *            or a base URI for a whole class of content.
     * @param notifyForDescendants When false, the observer will be notified
     *            whenever a change occurs to the exact URI specified by
     *            <code>uri</code> or to one of the URI's ancestors in the path
     *            hierarchy. When true, the observer will also be notified
     *            whenever a change occurs to the URI's descendants in the path
     *            hierarchy.
     * @param observer The object that receives callbacks when changes occur.
     * @see #unregisterContentObserver
     */
    public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
            @NonNull ContentObserver observer) {
        Preconditions.checkNotNull(uri, "uri");
        Preconditions.checkNotNull(observer, "observer");
        registerContentObserver(
                ContentProvider.getUriWithoutUserId(uri),
                notifyForDescendants,
                observer,
                ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
    }
复制代码

我们在注册 ContentObserver 时,会传两个重要的参数,UrinotifyForDescendants,其中 Uri 就是系统发生变化的文件对应的 Uri,比如想监听系统图片变化,就使用 MediaStore.Images.Media.EXTERNAL_CONTENT_URI,第二个参数比较重要,大概意思就是是否要精确匹配 Uri,如果 false 代表要精确匹配,true 就不要,具体例子可以参考这篇文章 android notifyForDescendents 为false 的含义

这里直接借用一下文中的结论

假设UriMatcher 里注册的Uri共有一下类型: 1 、content://com.qin.cb/student (学生) 2 、content://com.qin.cb/student/# 3、 content://com.qin.cb/student/schoolchild(小学生,派生的Uri) 假设我们当前需要观察的Uri为content://com.qin.cb/student,如果发生数据变化的Uri为 content://com.qin.cb/student/schoolchild ,当notifyForDescendents为 false,那么该ContentObserver会监听不到, 但是当notifyForDescendents 为ture,能捕捉该Uri的数据库变化。

原来版本的 App 这个参数传的是 false ,最终在 Android Q 中传 true 解决了这个问题,为避免其他 Android 版本受到影响,最好做个版本判断

原因

具体原因还没细究,日后有空会分析原因,补上此部分