android.view.accessibility.CaptioningManager$1.onChange 中的 NullPointerException

NullPointerException in android.view.accessibility.CaptioningManager$1.onChange

我从我的应用程序中看到了奇怪的崩溃报告。

android.view.accessibility.CaptioningManager.onChange (CaptioningManager.java:226)
android.database.ContentObserver.onChange (ContentObserver.java:145)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:703)

http://crashes.to/s/db9e325f0f5

辅助功能开启时好像有问题。但是我如何才能检测到错误出现在哪个 UI 元素或屏幕上?

我尝试在自己的设备上启用辅助功能并浏览所有应用程序屏幕,但没有收到异常。

编辑

这个错误会不会是在TextView中使用Span引起的?

 // welcome text
 TextView welcome = (TextView) view.findViewById(R.id.home_user_name);
 welcome.setText(Html.fromHtml(getString(R.string.home_welcome_text, accountManager.getActiveUser())));
 // change...
 welcome.append(" ");
 SpannableString str = SpannableString.valueOf(getString(R.string.home_user_change));
 str.setSpan(new URLSpan(getString(R.string.home_user_change)) {
        @Override
        public void onClick(View view) {
            mGuiHandler.sendEmptyMessage(MESSAGE_CHANGE_USER);
        }
 }, 0, str.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 welcome.append(str);
 welcome.setMovementMethod(LinkMovementMethod.getInstance());

首先,这不是无障碍服务 API 的一部分。它是 View 可访问性实现的一部分。请参阅 google 代码项目。 CaptioningManager 在 core/java/android/view/accessibility 包中。因此,无论可访问性是否打开,或者至少与可能打开的可访问性服务无关,都会发生此崩溃。

在第 235 行的字幕管理器中(Google 代码上的版本已过时,但非常接近。)。 onChange函数是这样的:

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        final String uriPath = uri.getPath();
        final String name = uriPath.substring(uriPath.lastIndexOf('/') + 1);
        if (Secure.ACCESSIBILITY_CAPTIONING_ENABLED.equals(name)) {
            notifyEnabledChanged();
        } else if (Secure.ACCESSIBILITY_CAPTIONING_LOCALE.equals(name)) {
            notifyLocaleChanged();
        } else if (Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE.equals(name)) {
            notifyFontScaleChanged();
        } else {
            // We only need a single callback when multiple style properties
            // change in rapid succession.
            mHandler.removeCallbacks(mStyleChangedRunnable);
            mHandler.post(mStyleChangedRunnable);
        }
    }

这是由 ContentObserver class 调用的,从这一点开始:

    /**
 * Dispatches a change notification to the observer. Includes the changed
 * content Uri when available and also the user whose content changed.
 *
 * @param selfChange True if this is a self-change notification.
 * @param uri The Uri of the changed content, or null if unknown.
 * @param userId The user whose content changed. Can be either a specific
 *         user or {@link UserHandle#USER_ALL}.
 *
 * @hide
 */
public void onChange(boolean selfChange, Uri uri, int userId) {
    onChange(selfChange, uri);
}

ContentObserver 文档中的通知 class 明确指出 uri 可以为 null,但 CaptioningManager 立即调用 getPath 而不检查 fi 值为 null。这就是它崩溃的原因。传递给 onChange 的 uri 为 null。

现在,这是有点模糊的地方。其余部分是私有的,在 Google 代码上不可用。所以,我们只能猜测 zygote 在做什么。虽然,它可能不会有帮助,即使我们可以看到它。

现在,我们可以从中得到什么。在 CaptioningManager 的文档中,我们看到了以下对其用途的解释:

Contains methods for accessing and monitoring preferred video captioning state and visual properties.

因此,基于所有这些,检查任何 URI 或任何视频的其他属性以及应用程序中可能的其他媒体元素...