0

I have a MainActivity with the following layout :

<androidx.fragment.app.FragmentContainerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_host_fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph_main"/>

The rest are in the Fragments.

I have two Fragments where I animate the transition with shared elements such as a list fragment and a detail fragment.

I am using the Navigation Component from JetPack with the SafeArgs plugin alongside with transitions classes from the AndroidX package.

val directions = AlbumsListFragmentDirections.actionAlbumsListFragmentToAlbumDetailsFragment(
            ViewCompat.getTransitionName(binding.imageThumbnail)!!
        )

val extras = FragmentNavigatorExtras(
            binding.imageThumbnail to ViewCompat.getTransitionName(binding.imageThumbnail)!!
        )

findNavController().navigate(directions, extras)

I am also using postponeEnterTransition() and startPostponedEnterTransition() to trigger transitions animations when UI is ready to do so.


On any L+ devices, as Shared Elements Transitions are native components from the OS, there are no issue.

However, on my KitKat device (Samsung S4), since my min API is 19, the app crashes when calling the above code snippet with these crash logs:

java.lang.IllegalStateException: Views added to a FragmentContainerView must be associated with a Fragment. View androidx.transition.GhostViewApi14{42a33b30 V.ED.... ......ID 0,0-0,0} is not associated with a Fragment.
        at androidx.fragment.app.FragmentContainerView.addView(FragmentContainerView.java:276)
        at android.view.ViewGroup.addView(ViewGroup.java:3557)
        at android.view.ViewGroup.addView(ViewGroup.java:3533)
        at androidx.transition.GhostViewApi14.addGhost(GhostViewApi14.java:53)
        at androidx.transition.GhostViewUtils.addGhost(GhostViewUtils.java:30)
        at androidx.transition.ChangeTransform.createGhostView(ChangeTransform.java:391)
        at androidx.transition.ChangeTransform.createAnimator(ChangeTransform.java:272)
        at androidx.transition.Transition.createAnimators(Transition.java:744)
        at androidx.transition.TransitionSet.createAnimators(TransitionSet.java:470)
        at androidx.transition.TransitionSet.createAnimators(TransitionSet.java:470)
        at androidx.transition.TransitionSet.createAnimators(TransitionSet.java:470)
        at androidx.transition.Transition.playTransition(Transition.java:1821)
        at androidx.transition.TransitionManager$MultiListener.onPreDraw(TransitionManager.java:300)
        at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:879)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2131)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1236)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6471)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
        at android.view.Choreographer.doCallbacks(Choreographer.java:603)
        at android.view.Choreographer.doFrame(Choreographer.java:573)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:157)
        at android.app.ActivityThread.main(ActivityThread.java:5356)
        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:1265)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
        at dalvik.system.NativeStart.main(Native Method)

The error is simple to understand: FragmentContainerView does not support any views that are not associated with a Fragment. And apparently, there's a androidx.transition.GhostViewApi14 at the root of this crash.

Looking into the source code of this class, I learned it's a backport for a native view added in L to support transitions I believe.

I attempted to fix that issue by reverting back to the old way, in XML file for my MainActivity declared in land-v19:

<fragment
    android:name="androidx.navigation.fragment.NavHostFragment"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_host_fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph_main"/>

However, the app still crashes on my KitKat device. Is it possible the framework (maybeAppCompat - I'm using stable version 1.1.0 with activity-ktx-1.1.0'?) automatically replaces <fragment> by a FragmentContainerView ? It appears so, because I removed that XML layout, and pasted its content in the original one. Simply put, all versions will use that XML with <fragment>

Is that a bug ? If so, should it be reported or is it known ? Or am I doing something wrong ?

Thanks for the help !

Mackovich
  • 3,319
  • 6
  • 35
  • 73

1 Answers1

0

I was able to fix that particular issue and have transitions fully work on my KitKat devices.

As I was testing the app on a Android 10 (Q) device, I stumbled into this issue where the transitions would not work, but would not crash the app. Looking at the logs, it would see method reflection from / with the Ghost View API would failed because Android 10 imposes limitations on the reflections logic.

My issue is also related to that Ghost View API.

The solution, provided by a developer working on that API, was to upgrade to a more recent and stable AndroidX Transition API version that fixed that particular issue.

At the time of writing this answer, the most stable version is 1.3.1.

It fixed both issues. Question solved.

I was quite lucky to stumble on this issue which solution would solve mine!

Mackovich
  • 3,319
  • 6
  • 35
  • 73