Android 4.4 KitKat 随机崩溃
Posted
技术标签:
【中文标题】Android 4.4 KitKat 随机崩溃【英文标题】:Android 4.4 KitKat random crash 【发布时间】:2013-12-24 03:23:03 【问题描述】:编辑:在否决和暗示事情之前,请理解我无法重现此错误。这在我无法访问的某些设备上经常发生,但在固件重置后不会发生!
我最近在为客户开发的应用程序中发现了随机崩溃。 3 年后,该应用现在拥有大约 100,000 名活跃用户。
我们已经看到 Nexus 4 和 5 上的崩溃,两者都使用 android 4.4 KitKat。
我们无法在运行 4.4 的 Nexus 4 和 5 上重现它。
通过我们的支持,我们有了一位客户。他告诉我们,每次调用新活动时都会在同一个地方发生崩溃。他在经营 Dalvik,而不是 ART。重置固件后,应用程序运行良好,无法再次重现!
出于法律原因,我无法发布源代码或布局,但有此堆栈跟踪:
java.lang.RuntimeException: Unable to start activity ComponentInfoxx.xxx.xxxxx.xxx.xxxxxx.prod/xx.xxx.xxxxx.xxx.PaymentsActivity: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2176)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226)
at android.app.ActivityThread.access$700(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4998)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:126)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.view.View.sendAccessibilityEventUncheckedInternal(View.java:4938)
at android.view.View.sendAccessibilityEventUnchecked(View.java:4919)
at android.view.View$SendViewStateChangedAccessibilityEvent.run(View.java:19433)
at android.view.View$SendViewStateChangedAccessibilityEvent.runOrPost(View.java:19465)
at android.view.View.notifyViewAccessibilityStateChangedIfNeeded(View.java:7265)
at android.view.View.setFlags(View.java:8990)
at android.view.View.setVisibility(View.java:6020)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:859)
at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method)
at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:547)
at android.view.LayoutInflater.parseInclude(Native Method)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:745)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method)
at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:547)
at android.view.LayoutInflater.inflate(Native Method)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
at android.app.Activity.setContentView(Activity.java:1928)
at xx.xxx.xxxxx.xxx.StandardActivity.setContentView(StandardActivity.java:289)
at xx.xxx.xxxxx.xxx.PaymentsActivity.onCreate(PaymentsActivity.java:61)
at android.app.Activity.performCreate(Activity.java:5243)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)
... 12 more
编辑:没有 xposed 的第二个堆栈跟踪
java.lang.RuntimeException: Unable to start activity ComponentInfoxx.xxx.xxxxx.xxx.xxxxx.prod/xx.xxx.xxxxx.xxx.PaymentsActivity: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2176)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226)
at android.app.ActivityThread.access$700(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4998)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at android.view.View.sendAccessibilityEventUncheckedInternal(View.java:4938)
at android.view.View.sendAccessibilityEventUnchecked(View.java:4919)
at android.view.View$SendViewStateChangedAccessibilityEvent.run(View.java:19433)
at android.view.View$SendViewStateChangedAccessibilityEvent.runOrPost(View.java:19465)
at android.view.View.notifyViewAccessibilityStateChangedIfNeeded(View.java:7265)
at android.view.View.setFlags(View.java:8990)
at android.view.View.setVisibility(View.java:6020)
at android.view.LayoutInflater.parseInclude(LayoutInflater.java:859)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:745)
at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
at android.app.Activity.setContentView(Activity.java:1928)
at xx.xxx.xxxxx.xxx.StandardActivity.setContentView(StandardActivity.java:289)
at xx.xxx.xxxxx.xxx.PaymentsActivity.onCreate(PaymentsActivity.java:61)
at android.app.Activity.performCreate(Activity.java:5243)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)
... 11 more
在 setContentView() 中设置的布局包含框架,否则它非常标准和简单。
非常感谢任何输入 :-)
【问题讨论】:
问题可能出在布局上,也许this页面可以帮到你。检查你使用的东西是否在 4.4 中发生了变化。没有代码有点难。 一个 NPE 应该不难发现和解决 这样的框架代码中的 NPE 可能更难找到和解决,因为您无法直接控制该代码。虽然您可以从 AOSP 获取源代码,以便跟踪代码流并更好地了解 NPE 可能发生的原因。 另外,我不确定为什么对这个问题投反对票。对我来说,这似乎是一个完全合理的问题。 啊,好的。如果您在其他地方看到过该错误(即堆栈跟踪中没有 xposed 条目),那么这不太可能是问题所在。在这种情况下,我建议获取 AOSP 源代码并查看堆栈跟踪中提到的位置。您可以从那里向后工作,尝试确定此时会导致 NPE 的条件。 【参考方案1】:我在维护一些代码时也遇到了同样的问题。通过在辅助功能选项中启用 TalkBack,我能够始终如一地复制该错误。
首先,这是来自 Android 的 KitKat 版本的 View.java 中使用导致崩溃的空引用的方法:
void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event)
if (!isShown())
return;
onInitializeAccessibilityEvent(event);
// Only a subset of accessibility events populates text content.
if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0)
dispatchPopulateAccessibilityEvent(event);
// In the beginning we called #isShown(), so we know that getParent() is not null.
getParent().requestSendAccessibilityEvent(this, event);
对我来说,根本原因是一个自定义视图,它像这样覆盖了 View.isShown():
public boolean isShown()
return someCondition;
这意味着 sendAccessibilityEventUncheckedInternal 会运行通过 if(!isShown()) 检查,即使 View 有一个 null 父级,也会导致崩溃。
我最初认为这是一个并发问题,因为我假设 isShown() 检查确保父级不为空,并且在执行 sendAccessibilityEventUncheckedInternal 期间对视图的父级的引用已更改。错了!
如果您发现类似的问题,尤其是在您未编写的代码中,您可以通过包含超类的 isShown() 的结果来很容易地防止这种崩溃(假设您正在更改 View 的直接子类中的代码):
public boolean isShown()
return super.isShown() && someCondition;
【讨论】:
你摇滚,@Blammo 船长!实际上有一个 isShown() 的覆盖我仍然无法重现它,但会应用你建议的修复来查看它是否修复它:-) 这解决了一个类似的问题,因为我也创建了一个自定义View
并覆盖了 isShown()
方法。
这个回复救了我……显然我遇到了同样的问题。我的应用程序在三星设备上运行良好,但在 LGG3 设备上崩溃了!然而,这个修复解决了我的问题。谢谢!
完成!我再也没有听到或看到任何与这个问题相关的东西,所以它一定有效:)
谢谢老兄。编码愉快!【参考方案2】:
我的用户也遇到了同样的问题,这似乎是由打开了一个或多个辅助功能选项引起的。我的一些用户正在使用安装了辅助功能选项的 Pebble 智能手表 - 所以它不仅仅是 TalkBack 等。
诊断
在https://github.com/android/platform_frameworks_base/blob/kitkat-mr1-release/core/java/android/view/View.java#L9006 上看看KitKat 的View#setFlags()
方法
if (accessibilityEnabled)
...
notifyViewAccessibilityStateChangedIfNeeded(
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
这会将您送入以NullPointerException
结尾的兔子洞如果它在视图附加到视图层次结构之前执行(即没有父级),因为在View#sendAccessibilityEventUncheckedInternal()
@987654322 @我们有:
getParent().requestSendAccessibilityEvent(this, event);
我的解决方法(看起来对你不起作用)
对于我的应用程序,我正在以编程方式创建一个View
子类,并在构造函数中调用View#setOnClickListener()
。相反,我现在从
View#setOnClickListener()
@Override
protected void onAttachedToWindow()
super.onAttachedToWindow();
/* Due to a bug in how Android 4.4 handles accessibility options,
* we can't set the onClick listener until this View has a parent or we will
* get an NPE. */
setOnClickListener(this);
之所以有效,是因为在调用 View#onAttachedToWindow()
时,此 View
将有一个父级。
您的堆栈跟踪问题更大。您正在通过 XML 布局上的属性掉入兔子洞。我还没给你想出主意。一种想法是这只能在应用程序启动时发生 - 否则几乎所有 XML 布局的膨胀都会触发崩溃,因为有太多的路径可以让你通过View#setFlags()
。在我的应用程序中,这一点似乎是唯一的崩溃,它发生在应用程序启动时。这不是一个令人愉快的想法,但一种可能是重新排序以在以后扩展此视图。
【讨论】:
太棒了,@bpenrod !我猜这也是一个并发问题:void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) if (!isShown()) //<-- parent is not null return; ... // In the beginning we called #isShown(), so we know that getParent() is not null. getParent().requestSendAccessibilityEvent(this, event); //<-- parent is now null, same thread :-|
(编辑:^我不知道如何正确格式化该代码)或者调用路径中的某个人已将其设置为空。我需要再挖一些。
Method added in comment above以上是关于Android 4.4 KitKat 随机崩溃的主要内容,如果未能解决你的问题,请参考以下文章
透明状态栏 - Android 4.4 (KitKat) 之前
无法在 Android 4.4 KitKat 上快速关闭 ChunkedInputStream
android webview中的HTML文件输入(android 4.4,kitkat)
在 android 4.4+ 或 kitkat 中隐藏状态栏