android NullPointerException在updateLocaleListFromAppContext中崩溃

Ric*_*hie 14 android google-play

我在PlayStore上上传了一个应用,并从android.app.ActivityThread.updateLocaleListFromAppContext上遇到java.lang.NullPointerException崩溃

我尝试了很多在线搜索,以检查此错误可能来自何处。我不是专门针对代码中的任何内容使用此方法调用的。

java.lang.NullPointerException: 
  at android.app.ActivityThread.updateLocaleListFromAppContext (ActivityThread.java:5892)
  at android.app.ActivityThread.handleBindApplication (ActivityThread.java:6127)
  at android.app.ActivityThread.access$1200 (ActivityThread.java:240)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1797)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:214)
  at android.app.ActivityThread.main (ActivityThread.java:7076)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:494)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:965)
Run Code Online (Sandbox Code Playgroud)

如果有人知道解决方案,或者我可以在哪里开始解决此问题,请提供帮助。

Fur*_*kul 1

在检查问题评论以及出现此问题的设备后,发现它似乎特定于部分设备,例如 OnePlus 设备和三星 J 系列。共同点是它们都是 Android 9 设备。我已经检查了 Android 9 的源代码(这是第 5750 行的方法调用,这是第 5520 行的方法本身),我可以说这段代码与配置更改无关。虽然链接的行号并不完全相同,但它们在距离上是相关的(例如,来自源代码的5750 - 5520 = 280 ,来自堆栈跟踪的6127 - 5892 = 285。相当接近,但不准确) )所以我假设框架正在调用该部分。该方法ActivityThread.handleBindApplication在首次启动时调用,并且配置更改仅在活动重新创建时发生,应用程序的配置不会更改。至少,给定的方法不会再次被调用。

我还可以说该方法updateLocaleListFromAppContext被成功调用,并且代码在该方法内部崩溃,而不是在开始时崩溃。

这是代码的相关部分:

/**
 * The LocaleList set for the app's resources may have been shuffled so that the preferred
 * Locale is at position 0. We must find the index of this preferred Locale in the
 * original LocaleList.
 */
private void updateLocaleListFromAppContext(Context context, LocaleList newLocaleList) {
    final Locale bestLocale = context.getResources().getConfiguration().getLocales().get(0);
    final int newLocaleListSize = newLocaleList.size();
    for (int i = 0; i < newLocaleListSize; i++) {
        if (bestLocale.equals(newLocaleList.get(i))) {
            LocaleList.setDefault(newLocaleList, i);
            return;
        }
    }

    // The app may have overridden the LocaleList with its own Locale
    // (not present in the available list). Push the chosen Locale
    // to the front of the list.
    LocaleList.setDefault(new LocaleList(bestLocale, newLocaleList));
}
Run Code Online (Sandbox Code Playgroud)

现在,有几件事需要考虑,

  • 这取自 AOSP(开源项目),设备制造商通常会修改这些核心类。设备内部的方法可能已被修改,但可能性很小。
  • Google Play Console 有时会删除有关堆栈跟踪的信息。
  • 如果堆栈跟踪准确,则此方法只能在newLocaleList.size()调用时崩溃bestLocale.equals(newLocaleList.get(i))。原因是:当生成堆栈跟踪时,它们的异常始终包含最后一个代码,而其他行会留下另一个堆栈跟踪。
  • 另一种可能性是:由于 for 循环和 的使用newLocaleListSizenewLocaleList变量的大小可能在代码迭代时发生更改,从而导致 崩溃newLocaleList.get(i)。不过,这种可能性有点小,因为get(i)假设数据完整,该方法在崩溃时是可见的。

根据信息,最有可能的罪魁祸首是方法中的变量bestLocale和。newLocaleList在更多地检查源代码后,newLocaleList传递的变量是通过AppBindData它创建的,并通过处理程序向下传递,并且其信息在handleBindApplication. 该方法使用 Android 的PackageManager调用特定信息更新,它用于查询有关 APK/加载的应用程序的信息,例如其信息、清单数据、元数据、活动等...

此信息通常使用 IPC(或 AIDL)从系统传递到应用程序,并且该信息有时可能会损坏,从而导致此错误。因此,变量有可能为newLocaleList空。

由于这是系统中的一个问题,为了尽可能避免它,我只能建议以下几点:

  • 如果可能的话,分析设备本身,并查看应用程序是否在调试版本中崩溃,
  • 确保您的字符串完全转换为所有语言,并且您不依赖于默认语言(也称为具有所有字符串的主要语言,但特定配置没有它们,除非它们在translatable=false文件中标记为strings.xml
  • 检查 Firebase Crashlytics 中是否存在类似的报告(如果使用)(该报告可能不存在,因为应用程序在正确创建应用程序之前崩溃,但 Firebase 服务有时仍可以上传。它还可以包含有关堆栈跟踪的更多信息。)
  • 检查Android 9模拟器(官方模拟器和Genymotion模拟器)是否发生崩溃
  • 您还可以使用三星测试实验室的在线三星设备(尽管时间很短),看看是否可以观察到崩溃。您可能会获得完整的堆栈跟踪,它可以为您指明正确的方向。

这些是我的发现,希望它们在某种程度上有用。