使用 LayoutAnimationController.shouldAnimateLayout 反应原生 Android 崩溃

Posted

技术标签:

【中文标题】使用 LayoutAnimationController.shouldAnimateLayout 反应原生 Android 崩溃【英文标题】:React Native Android crash with LayoutAnimationController.shouldAnimateLayout 【发布时间】:2020-09-10 09:20:41 【问题描述】:

我的应用在 android 设备上的生产模式下崩溃。基本上它发生在 Android 10(三星、小米、华为、LGE)上。

堆栈跟踪

      Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.ViewParent android.view.View.getParent()' on a null object reference
       at com.facebook.react.uimanager.layoutanimation.LayoutAnimationController.shouldAnimateLayout (LayoutAnimationController.java:91)
       at com.facebook.react.uimanager.NativeViewHierarchyManager.manageChildren(NativeViewHierarchyManager.java:453)
atcom.facebook.react.uimanager.UIViewOperationQueue$ManageChildrenOperation.execute(UIViewOperationQueue.java:206)
       at com.facebook.react.uimanager.UIViewOperationQueue$1.run(UIViewOperationQueue.java:792)
       at com.facebook.react.uimanager.UIViewOperationQueue.flushPendingBatches(UIViewOperationQueue.java:903)
       at com.facebook.react.uimanager.UIViewOperationQueue.access$2400(UIViewOperationQueue.java:43)
       at com.facebook.react.uimanager.UIViewOperationQueue$DispatchUIFrameCallback.doFrameGuarded(UIViewOperationQueue.java:963)
       at com.facebook.react.uimanager.GuardedFrameCallback.doFrame(GuardedFrameCallback.java:29)
       at com.facebook.react.modules.core.ReactChoreographer$ReactChoreographerDispatcher.doFrame(ReactChoreographer.java:175)
       at com.facebook.react.modules.core.ChoreographerCompat$FrameCallback$1.doFrame(ChoreographerCompat.java:85)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:997)
       at android.view.Choreographer.doCallbacks(Choreographer.java:797)
       at android.view.Choreographer.doFrame(Choreographer.java:728)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:984)
       at android.os.Handler.handleCallback(Handler.java:883)
       at android.os.Handler.dispatchMessage(Handler.java:100)
       at android.os.Looper.loop(Looper.java:237)
       at android.app.ActivityThread.main(ActivityThread.java:8016)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1076)

React Native 版本:

System:
    OS: macOS 10.15.4
    CPU: (4) x64 Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz
    Memory: 405.76 MB / 8.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 13.13.0 - /usr/local/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.5 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.1 - /usr/local/bin/pod
  SDKs:
    ios SDK:
      Platforms: iOS 13.7, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
    Android SDK:
      API Levels: 28, 29
      Build Tools: 28.0.3, 29.0.0, 29.0.2, 29.0.3
      System Images: android-22 | Google APIs Intel x86 Atom, android-24 | Google APIs Intel x86 Atom, android-24 | Google Play Intel x86 Atom, android-26 | Google Play Intel x86 Atom, android-29 | Google Play Intel x86 Atom, android-30 | Google APIs Intel x86 Atom
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6514223
    Xcode: 11.7/11E801a - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_242-release - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: 16.11.0 => 16.11.0 
    react-native: 0.62.0 => 0.62.0 
  npmGlobalPackages:
    *react-native*: Not Found

我有带有动画变量的文件:

import  LayoutAnimation, LayoutAnimationConfig  from 'react-native';

export const AnimationVars = 
  layoutAnimation: 
    keyboard,
    expandCollapse:  ...LayoutAnimation.Presets.easeInEaseOut, duration: expandCollapseDuration  as LayoutAnimationConfig,
    inputField:  ...LayoutAnimation.Presets.easeInEaseOut, duration: inputFieldDuration  as LayoutAnimationConfig,
    dialogTransform:  ...LayoutAnimation.Presets.easeInEaseOut, duration: expandCollapseDuration  as LayoutAnimationConfig,
    navBarTransform:  ...LayoutAnimation.Presets.easeInEaseOut, duration: navBarDuration  as LayoutAnimationConfig,
  ,
;

在我的应用程序的不同位置使用 var 之后,例如在切换方法中的 TitleExpanding 组件中:

  private _onToggle(nextValue: boolean, animate: boolean = true) 
    const rotateValue = !nextValue ? 1 : 0;
    if (animate) 
      requestAnimationFrame(() => 
        timing(this._rotateValue, 
          toValue: rotateValue,
          duration: AnimationVars.expandCollapseDuration,
          easing: Easing.linear,
        ).start();
      );
      LayoutAnimation.configureNext(AnimationVars.layoutAnimation.expandCollapse);
     else 
      this._rotateValue.setValue(rotateValue);
    
    this._toggle.toggle();

    const preferencesKey = this.props.preferencesKey;
    if (preferencesKey) 
      this._preferences.set(preferencesKey, nextValue ? 'false' : 'true').then();
    
  

我认为这是类似的问题https://github.com/facebook/react-native/issues/25832。如果有人遇到同样的错误,请告诉我。

【问题讨论】:

【参考方案1】:

我遇到了一个类似的问题,它围绕着我旋转,有一个带有按钮的 Modal 可以触发 LayoutAnimation。我发现的一种解决方案是将LayoutAnimation.configureNext 包装在setImmediate 中,例如

setImmediate(() => LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut));

这具有在执行操作之前允许模态足够的时间来移除的效果。

【讨论】:

以上是关于使用 LayoutAnimationController.shouldAnimateLayout 反应原生 Android 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)