All of my SceneForm AR projects started to crash with runtime exceptions

Jun 20, 2020

TL;DR

Your app is probably upgraded to AndroidX. By the new instructions of the Sceneform SDK README you need to have the two directories of Sceneform SDK as part of your project instead of depending on a package. Consequently you need to upgrade Sceneform SDK’s source code to AndroidX.

The Story

Sceneform is a magnificent library which allows an unparalleled high abstraction level entry to Augmented Reality. I have several AR projects in the works using Sceneform, one example is an AR Map to help attendees with the orientation in our conference venue, it augments large signs marking the classrooms. See my further blog posts about it: part 1 and part 2.

The synthesized scene generation didn’t work and I got down into the rabbit hole of CompletableFutures (also see here). After some more struggle I managed to solve the problem and now the concept of using textures on simple slabs (instead of extruded numbers modeled by Blender) works. Some new issues arise, like the lightning makes the white-on-red texture strong colors to appear quite washed out, but I’ll solve these as well eventually.

Recently I started another Augmented Reality project using newest androidx libraries instead of old AppCompat ones and also using newest 1.16+ Sceneform SDK and surprisingly I hit some weird runtime crashes. First I got side tracked, because I started to use androidx.preference:preference:1.1.1 to eliminate plumbing code with my Settings view. As a side effect Android Studio suggests to replace <fragment> element of the ARFragment’s layout with a <androidx.fragment.app.FragmentContainerView>. That’s a trap though and don’t fall for it: it’ll lead to a NullPointerException:

E/Perf: Fail to get file list com.example.sceneform
    getFolderSize() : Exception_1 = java.lang.NullPointerException: Attempt to get length of null array
W/ample.scenefor: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
W/ample.scenefor: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.sceneform, PID: 5729
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sceneform/com.example.sceneform.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.ar.sceneform.Scene com.google.ar.sceneform.ArSceneView.getScene()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3374)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3513)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2109)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7682)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.ar.sceneform.Scene com.google.ar.sceneform.ArSceneView.getScene()' on a null object reference
        at com.example.sceneform.MainActivity.onCreate(MainActivity.java:76)
        at android.app.Activity.performCreate(Activity.java:7815)
        at android.app.Activity.performCreate(Activity.java:7804)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1318)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3349)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3513) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2109) 
        at android.os.Handler.dispatchMessage(Handler.java:107) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7682) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) 
I/Process: Sending signal. PID: 5729 SIG: 9

This derailed me for a while but then I tried to undo changes I made one-by-one. And when that didn’t help I went back to other projects’ source codes which knowingly worked in the past (like the DevFest AR Map is actually released in the App Store). That’s when I realized I was dealing with something bigger, because every project now produced the same Exception chain:

E/Perf: Fail to get file list com.example.sceneform
E/Perf: getFolderSize() : Exception_1 = java.lang.NullPointerException: Attempt to get length of null array
W/ample.scenefor: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
W/ample.scenefor: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.sceneform, PID: 30804
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sceneform/com.example.sceneform.MainActivity}: android.view.InflateException: Binary XML file line #23 in com.example.sceneform:layout/activity_main: Binary XML file line #22 in com.example.sceneform:layout/sceneform_ux_fragment_layout: Binary XML file line #22 in com.example.sceneform:layout/sceneform_ux_fragment_layout: Error inflating class com.google.ar.sceneform.ArSceneView
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3374)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3513)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2109)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7682)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
     Caused by: android.view.InflateException: Binary XML file line #23 in com.example.sceneform:layout/activity_main: Binary XML file line #22 in com.example.sceneform:layout/sceneform_ux_fragment_layout: Binary XML file line #22 in com.example.sceneform:layout/sceneform_ux_fragment_layout: Error inflating class com.google.ar.sceneform.ArSceneView
     Caused by: android.view.InflateException: Binary XML file line #22 in com.example.sceneform:layout/sceneform_ux_fragment_layout: Binary XML file line #22 in com.example.sceneform:layout/sceneform_ux_fragment_layout: Error inflating class com.google.ar.sceneform.ArSceneView
     Caused by: android.view.InflateException: Binary XML file line #22 in com.example.sceneform:layout/sceneform_ux_fragment_layout: Error inflating class com.google.ar.sceneform.ArSceneView
     Caused by: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Constructor.newInstance0(Native Method)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
        at android.view.LayoutInflater.createView(LayoutInflater.java:854)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1006)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
        at com.google.ar.sceneform.ux.BaseArFragment.onCreateView(BaseArFragment.java:162)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
        at androidx.fragment.app.FragmentManagerImpl.ensureInflatedFragmentView(FragmentManagerImpl.java:1138)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:851)
        at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1133)
        at androidx.fragment.app.FragmentManagerImpl.addFragment(FragmentManagerImpl.java:1393)
        at androidx.fragment.app.FragmentManagerImpl.onCreateView(FragmentManagerImpl.java:3205)
        at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:134)
        at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:357)
        at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:336)
        at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1069)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:997)
        at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:961)
E/AndroidRuntime:     at android.view.LayoutInflater.rInflate(LayoutInflater.java:1123)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
        at android.view.LayoutInflater.parseInclude(LayoutInflater.java:1263)
        at android.view.LayoutInflater.rInflate(LayoutInflater.java:1119)
        at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1084)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:682)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:534)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:481)
        at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:555)
        at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:161)
        at com.example.sceneform.MainActivity.onCreate(MainActivity.java:59)
        at android.app.Activity.performCreate(Activity.java:7815)
        at android.app.Activity.performCreate(Activity.java:7804)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1318)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3349)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3513)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2109)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7682)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
     Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/filament/gltfio/Gltfio;
        at com.google.ar.sceneform.rendering.EngineInstance.gltfioInit(EngineInstance.java:96)
        at com.google.ar.sceneform.rendering.EngineInstance.createEngine(EngineInstance.java:110)
        at com.google.ar.sceneform.rendering.EngineInstance.getEngine(EngineInstance.java:42)
        at com.google.ar.sceneform.rendering.Renderer.initialize(Renderer.java:542)
        at com.google.ar.sceneform.rendering.Renderer.<init>(Renderer.java:109)
        at com.google.ar.sceneform.SceneView.initialize(SourceFile:37)
        at com.google.ar.sceneform.SceneView.<init>(SourceFile:13)
        at com.google.ar.sceneform.ArSceneView.<init>(SourceFile:10)
        	... 48 more
     Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.android.filament.gltfio.Gltfio" on path: DexPathList[[zip file "/data/app/com.example.sceneform-wiYXdRfeb7wSS91CFPS9tw==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.sceneform-wiYXdRfeb7wSS91CFPS9tw==/lib/arm64, /data/app/com.example.sceneform-wiYXdRfeb7wSS91CFPS9tw==/base.apk!/lib/arm64-v8a, /system/lib64, /system/product/lib64]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:196)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        	... 56 more
I/Process: Sending signal. PID: 30804 SIG: 9
Disconnected from the target VM, address: 'localhost:8628', transport: 'socket'

Sometimes the Binary XML file line number is #23 instead of #22. We also see something about com.google.android.filament.gltfio.Gltfio which have not yielded any Google search results whatsoever. I went to the Sceneform SDK’s GitHub page but that is in an archived state now, therefore I could not file a new issue and I also could not comment on any existing issues. There were a few issues with similar call stacks: issue #4 and issue #188. The first suggested OpenGL ES version problem and I could rule that out since I have v3.1. The sample code checked that BTW, so I’d get an alert if it was a problem, although the check was in the AR Fragment’s code and that was crashing during the inflate. The second issue suggested 1.8 Java version change in the gradle compileOptions, but I had that already as well. As I mentioned I could not comment to the issues about my problems, or even signal a thumbs up - EXTREMELY frustrating. I filed an issue with the Sceneform Intro code lab repository but I haven’t heard back anything for several weeks. But even the Sceneform SDK has more than 560 open issues. That’s alarming and sad.

The last thing I suspected was that the Sceneform v1.16 SDK would have any breaking change compared to v1.15 or earlier, given that we were talking about minor version bumps. I accidentally glanced at the main README of the Sceneform SDK github repository and some instructions caught my eyes I haven’t seen before: you are supposed to copy two directories of the SDK and make them part of your project. Say what? This approach is concerning, because Sceneform wouldn’t be a package dependency any more and in the future someone would need to manually merge changes in there. But this was a step towards the good direction. I’d also need to duplicate this into any project I have. Besides a copy it still needed some more steps:

  1. settings.gradle and build.gradle needed to be changed as the Sceneform SDK’s new README steps described.
  2. com.google.ar.sceneform.ux:sceneform-ux:1.17.0 implementation dependency needed to be removed from my gradle.build file, otherwise the included source code classes would collide with the package’s classes and I’d get a ton of duplicate classes errors during compile.
  3. The included source directories needed to be refactored to use the AndroidX libraries instead of the older AppCompat ones. I saw that several of the 400+ forks of the SDK repository already did that. My approach is to make minimal set of changes however. versus forks seemingly applied their own code styles (indentation rules and other coding style changes): that tricks the diff tool to sense more change than semantically actually happening and would more likely cause a merge conflict in the future if ever the source gets patched and you need to bring that into your project.

These series of steps together solved the runtime errors. The fact that Sceneform SDK repository is in an archived state - sad and concerning.

Comments loading...