ViewDataBinding 导致在 activity.finish() 后恢复应用程序崩溃,NPE 在视图附件期间访问 mRebindRunnable
Posted
技术标签:
【中文标题】ViewDataBinding 导致在 activity.finish() 后恢复应用程序崩溃,NPE 在视图附件期间访问 mRebindRunnable【英文标题】:ViewDataBinding causes crash resuming app after activity.finish(), NPE on access to mRebindRunnable during view attachment 【发布时间】:2020-12-15 20:01:55 【问题描述】:成功启动 Activity 后崩溃表面,膨胀带有数据绑定的片段。在根级别按下后退按钮后,应用程序(正确地)通过activity.finish()
但将应用程序实例保留在后台。
重新启动时,应用在创建视图后的某个时间点崩溃(至少基于调试)。
崩溃:
2020-08-26 20:00:50.626 9706-9706/com.org.app.dev E/androidRuntime: FATAL EXCEPTION: main
Process: com.org.app.dev, PID: 9706
java.lang.NullPointerException: Attempt to read from field 'java.lang.Runnable androidx.databinding.ViewDataBinding.mRebindRunnable' on a null object reference
at androidx.databinding.ViewDataBinding.access$100(ViewDataBinding.java:65)
at androidx.databinding.ViewDataBinding$6.onViewAttachedToWindow(ViewDataBinding.java:165)
at android.view.View.dispatchAttachedToWindow(View.java:19564)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3437)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2028)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1721)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7598)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:966)
at android.view.Choreographer.doCallbacks(Choreographer.java:790)
at android.view.Choreographer.doFrame(Choreographer.java:725)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:951)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
挖掘源代码,调试,我能收集到的最好的结果是 ViewDataBinding 看到以前绑定的视图已重新附加,并尝试与现有资源重新绑定。但是,它显然失去了对静态可运行文件的引用。来自 ViewDataBinding 的相关源码:
private static final OnAttachStateChangeListener ROOT_REATTACHED_LISTENER;
static
if (VERSION.SDK_INT < VERSION_CODES.KITKAT)
ROOT_REATTACHED_LISTENER = null;
else
ROOT_REATTACHED_LISTENER = new OnAttachStateChangeListener()
@TargetApi(VERSION_CODES.KITKAT)
@Override
public void onViewAttachedToWindow(View v)
// execute the pending bindings.
final ViewDataBinding binding = getBinding(v);
binding.mRebindRunnable.run();
v.removeOnAttachStateChangeListener(this);
@Override
public void onViewDetachedFromWindow(View v)
;
我确实注意到来自App crash caused by data binding related to java.lang.Runnable android.databinding.ViewDataBinding.mRebindRunnable 的相同堆栈跟踪,但该问题似乎与应用程序立即崩溃有关(我的问题仅在尝试补充水分后发生)。但是从那个问题来看,我确实注意到记录我的视图标签会返回 null。我尝试在xml中设置一个静态标签,没有任何变化。
我尝试过的其他事情:
如果我只实例化片段,则不会出现问题(但显然没有附加到框架布局 没有明确的调试崩溃点(onCreateView、onViewCreated 都被调用) 我尝试更改膨胀、分配生命周期所有者、绑定视图模型的方式;没有任何更改影响崩溃。 我尝试对绑定进行一些调用(invalidateAll()、unbind()),但没有成功。同样,只有在应用程序实例仍然存在但活动已被破坏时才会出现此问题。感谢您的任何提示!
编辑:相关代码位
活动(Java)-
ExampleFragment exampleFragment = new ExampleFragment(exampleParameter);
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager
.beginTransaction()
.add(R.id.example_frame_layout, exampleFragment, EXAMPLE_TAG)
.commit();
片段(Kotlin)-
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View?
binding = FragmentExampleBinding.inflate(inflater, container, false).apply
lifecycleOwner = viewLifecycleOwner
return binding.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
super.onViewCreated(view, savedInstanceState)
binding.run
viewModel = this@ExampleFragment.viewModel
更新
有趣的是,当我尝试将相同的片段(新实例化)膨胀到不同的(未启动)活动时,我现在看到了这一点。调试这种情况,除了在膨胀并返回绑定的根视图(而不是 null)后遇到崩溃之外,我找不到任何问题。我已经尝试过为布局创建的静态方法以及 DataBindingUtil。两者都经历了同样的崩溃。
【问题讨论】:
您需要包含您的代码。 感谢@GavinWright 观看。我试图添加相关的代码位。 (活动在 java 中,片段在 Kotlin 中)。如前所述,我尝试更改视图的绑定方式(片段代码)并且没有看到任何区别。我还想到了在活动销毁期间没有收集垃圾的片段或活动的实例。我尝试使用内存分析工具,但我不确定要查找什么。好奇是否有人成功识别了活动/片段泄漏,以及它是如何显示在内存分析工具上的。 【参考方案1】:尤里卡!!
<merge/>
不仅不能用于 <include/>
布局(这里也有相关文档:https://developer.android.com/topic/libraries/data-binding/expressions#includes)
但是
绑定也不适用于以 <merge/>
为根的 <include/>
布局。看起来是这样的:
<layout>
...
<include layout="id/sub_layout"
bind:viewModel="@viewModel />
...
</layout>
以及问题(R.id.sub_layout.xml):
<layout>
...
<merge>
<TextView/>
<ImageView/>
</merge>
...
</layout>
奇怪的是它似乎在启动活动中起作用,但很高兴知道导致这种情况的症状(通货膨胀后异步崩溃)。 对于遇到数据绑定问题和错误消息不佳的人,我绝对建议您尝试更改您的布局。
【讨论】:
以上是关于ViewDataBinding 导致在 activity.finish() 后恢复应用程序崩溃,NPE 在视图附件期间访问 mRebindRunnable的主要内容,如果未能解决你的问题,请参考以下文章
android studio 中的数据绑定基础。 ActivitymainBinding 不是 ViewDataBinding 的子类型
数据绑定 Android - 类型参数 T 具有不兼容的上限:ViewDataBinding 和 MainActivity
Data Binding Android - Type parameter T has incompatible upper bounds : ViewDataBinding and MainAct(