简体   繁体   English

ViewDataBinding 导致应用程序在activity.finish() 之后崩溃恢复,NPE 在视图附件期间访问 mRebindRunnable

[英]ViewDataBinding causes crash resuming app after activity.finish(), NPE on access to mRebindRunnable during view attachment

Crash surfaces after successfully launching an activity, inflating a fragment w/ data binding.成功启动活动后崩溃表面,膨胀带有数据绑定的片段。 After pressing the back button at the root level, the app (properly) goes through an activity.finish() but keeps the application instance in the background.在根级别按下后退按钮后,应用程序(正确地)通过一个activity.finish()但将应用程序实例保留在后台。 Upon relaunching, the app crashes at some point after the view is created (at least based on debugging).重新启动时,应用程序在创建视图后的某个时间点崩溃(至少基于调试)。

The crash:迷恋;撞车;崩溃:

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)

Digging into source, debugging, the best I can gather is the ViewDataBinding sees that a formerly bound view has reattached, and attempts to rebind with existing resources.深入研究源代码,调试,我能收集到的最好的是 ViewDataBinding 看到以前绑定的视图已重新附加,并尝试与现有资源重新绑定。 However, it's obviously lost it's reference to the static runnable.但是,它显然丢失了对静态可运行对象的引用。 Relative source code from 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) {
                }
            };
        }
    }

I did notice the same stack trace from: App crash caused by data binding related to java.lang.Runnable android.databinding.ViewDataBinding.mRebindRunnable but that issue seems to talk about the app crashing instantly (mine only occurs after attempting to rehydrate).我确实注意到了来自以下内容的相同堆栈跟踪: App crash cause of data binding related to java.lang.Runnable android.databinding.ViewDataBinding.mRebindRunnable但该问题似乎与应用程序立即崩溃有关(我的仅在尝试补水后发生)。 But from that issue, I did note that logging my view tag comes back null.但是从那个问题来看,我确实注意到记录我的视图标签返回空值。 I tried setting a static tag in xml, with no change.我尝试在 xml 中设置一个静态标签,没有任何变化。

Other things I've tried:我尝试过的其他事情:

  • If I only instantiate the fragment, the issue doesn't occur (but obviously doesn't attach to the framelayout如果我只实例化片段,则不会发生问题(但显然不会附加到框架布局
  • No clear debugging crash point (onCreateView, onViewCreated are both called)没有明确的调试崩溃点(onCreateView、onViewCreated 都被调用)
  • I tried changing how I inflate, assign lifecycleowner, bind the viewmodel;我尝试改变我如何膨胀,分配生命周期所有者,绑定视图模型; No change affected the crash.没有任何变化影响崩溃。
  • I tried making some calls into the binding (invalidateAll(), unbind()) with no success.我尝试对绑定进行一些调用(invalidateAll()、unbind()),但没有成功。

Again, the issue only crops up when the application instance is still alive, but the activity has been destroyed.同样,该问题仅在应用程序实例仍然存在但活动已被销毁时才会出现。 Thanks for any tips!!感谢您的任何提示!

EDIT: Relevant code bits编辑:相关代码位

Activity (Java) -活动 (Java) -

ExampleFragment exampleFragment = new ExampleFragment(exampleParameter);
FragmentManager fragmentManager = getSupportFragmentManager();

fragmentManager
        .beginTransaction()
        .add(R.id.example_frame_layout, exampleFragment, EXAMPLE_TAG)
        .commit();

Fragment (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
    }
}

UPDATE更新

Interestingly enough, I'm now seeing this when I try to inflate the same fragment (freshly instantiated) into a different (not-launch) activity.有趣的是,当我尝试将相同的片段(新实例化的)膨胀到不同的(非启动)活动时,我现在看到了这一点。 Debugging this case, I can't find any issues beyond experiencing the crash after inflating AND returning the binding's root view (instead of null).调试这个案例,除了在膨胀和返回绑定的根视图(而不是 null)之后遇到崩溃之外,我找不到任何问题。 I have tried with both the created static method for the layout as well as the DataBindingUtil.我已经尝试使用为布局创建的静态方法以及 DataBindingUtil。 Both experience the same crash.两者都经历了相同的崩溃。

Eureka!!尤里卡!!

Not only can <merge/> not be used to <include/> layouts (as well documented here: https://developer.android.com/topic/libraries/data-binding/expressions#includes ) <merge/>不仅不能用于<include/>布局(这里也有记录: https : //developer.android.com/topic/libraries/data-binding/expressions#includes

BUT

Binding also DOES NOT work across <include/> layouts that have <merge/> at the root.绑定也不适用于以<merge/>为根的<include/>布局。 Here's what that looks like:这是它的样子:

<layout>
...

    <include layout="id/sub_layout"
        bind:viewModel="@{viewModel} />
...
</layout>

And the issue (R.id.sub_layout.xml):和问题(R.id.sub_layout.xml):

<layout>
...
    <merge>
        <TextView/>
        <ImageView/>
    </merge>
...
</layout>

Strange that it seemed to work on the launch activity, but good to know the symptoms (crash async after inflation) that lead to this.奇怪的是它似乎对发射活动有效,但很高兴知道导致这种情况的症状(通货膨胀后崩溃异步)。 For folks having troubles with data binding and poor error messages, I would absolutely recommend trying changes to your layout.对于在数据绑定和错误消息方面有问题的人,我绝对建议您尝试更改您的布局。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM