2

I've a weird crash, apparently unfixable happening on Samsung devices only running Android 8.0.

I've a recyclerView populated in a Fragment that it's launching an Activity.

Here is my ItemHolder layout

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="@dimen/table_card_header_size"
android:transitionName="@string/team_profile_transition"
android:id="@+id/tableRowMainContainer"
android:background="@drawable/rounded_rect_top"
> ...

Here's is my Intent to the activity with the shared element

private val teamProfileOnClick = View.OnClickListener { v ->
    val teamContainer = v.findViewById<FrameLayout>(R.id.tableRowMainContainer)
    val tag = v.tag as TableRow
    val intent = Intent(context, TeamProfileActivity::class.java)
    intent.putExtra(TeamProfileActivity.TEAM_ID_PROFILE, tag.teamId)
    intent.putExtra(TeamProfileActivity.TEAM_NAME, tag.team.name)
    intent.putExtra(TeamProfileActivity.TEAM_COMPETITION_ID, tableCompetitionId)
    intent.putExtra(TeamProfileActivity.TEAM_TYPE, tag.team.teamType)

    val options = ActivityOptionsCompat.makeSceneTransitionAnimation(context as Activity,
            teamContainer,
            ViewCompat.getTransitionName(teamContainer))
    context.startActivity(intent, options.toBundle())
}

And here is the layout of the destination activity

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tool="http://schemas.android.com/tools"
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:transitionName="@string/team_profile_transition"
app:cardCornerRadius="10dp"
> ...

Here is the crash log

java.lang.NullPointerException: 
  at android.app.ActivityTransitionCoordinator.setSharedElementState (ActivityTransitionCoordinator.java:553)
  at android.app.ActivityTransitionCoordinator.setSharedElementState (ActivityTransitionCoordinator.java:653)
  at android.app.EnterTransitionCoordinator.startSharedElementTransition (EnterTransitionCoordinator.java:428)
  at android.app.EnterTransitionCoordinator.-wrap4 (Unknown Source)
  at android.app.EnterTransitionCoordinator$3.lambda$-android_app_EnterTransitionCoordinator$3_18867 (EnterTransitionCoordinator.java:492)
  at android.app.-$Lambda$CsyQO--8YdRe5wlajUCi-L98enA$1.$m$0 (Unknown Source:8)
  at android.app.-$Lambda$CsyQO--8YdRe5wlajUCi-L98enA$1.run (Unknown Source)
  at android.app.ActivityTransitionCoordinator.startTransition (ActivityTransitionCoordinator.java:902)
  at android.app.EnterTransitionCoordinator$3.lambda$-android_app_EnterTransitionCoordinator$3_18819 (EnterTransitionCoordinator.java:491)
  at android.app.-$Lambda$CsyQO--8YdRe5wlajUCi-L98enA$2.$m$0 (Unknown Source:8)
  at android.app.-$Lambda$CsyQO--8YdRe5wlajUCi-L98enA$2.run (Unknown Source)
  at com.android.internal.view.OneShotPreDrawListener.onPreDraw (OneShotPreDrawListener.java:78)
  at android.view.ViewTreeObserver.dispatchOnPreDraw (ViewTreeObserver.java:1045)
  at android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:2800)
  at android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:1779)
  at android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:7810)
  at android.view.Choreographer$CallbackRecord.run (Choreographer.java:911)
  at android.view.Choreographer.doCallbacks (Choreographer.java:723)
  at android.view.Choreographer.doFrame (Choreographer.java:658)
  at android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:897)
  at android.os.Handler.handleCallback (Handler.java:789)
  at android.os.Handler.dispatchMessage (Handler.java:98)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6938)
  at java.lang.reflect.Method.invoke (Native Method)
  at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:327)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)
DoM4
  • 91
  • 1
  • 7

2 Answers2

0

The solution I found is the following : Freeze/unfreeze the recyclerView when opening the shared element :

 override fun onPause() {
    super.onPause()
    tableCardStack.isLayoutFrozen = true
}

override fun onResume() {
    super.onResume()
    tableCardStack.isLayoutFrozen = false
}

What I've noticed was that the view I was animating was not animating back to the right position. So I thought to freeze the layout. I know it's not the best solution but I couldn't find anything better

DoM4
  • 91
  • 1
  • 7
0

Looks like certain Samsung devices don't check if the views parent is null which can happen in some edge cases. You can prevent this crash from happening by removing the views without parents from the transition. This is done by adding a SharedElementCallback to your activity and overwriting onSharedElementEnd and/or onSharedElementStart (depending on whether its your Enter or Exit transition that is crashing) and then finding and removing the views like this:

activity.setEnterSharedElementCallback(object : SharedElementCallback() {

    override fun onSharedElementStart(sharedElementNames: MutableList<String>?, sharedElements: MutableList<View>?, sharedElementSnapshots: MutableList<View>?) {
        sharedElements?.removeAll(sharedElements.filter { it.parent == null })
        super.onSharedElementStart(sharedElementNames, sharedElements, sharedElementSnapshots)
    }

    override fun onSharedElementEnd(sharedElementNames: MutableList<String>?, sharedElements: MutableList<View>?, sharedElementSnapshots: MutableList<View>?) {
        sharedElements?.removeAll(sharedElements.filter { it.parent == null })
        super.onSharedElementEnd(sharedElementNames, sharedElements, sharedElementSnapshots)
    }
}

Be aware that this does not remove the root cause of the crash, only prevents it from happening by not animating the view without a parent.