Common Item Failover for Lollipop Devices

I use the ActivityOptions.makeSceneTransitionAnimation API to handle common transitions.

The problem I am facing is that it works on Marshmellow devices, but it crashes on Lolipop Devices.

This is the crash log:

 Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.ViewGroup.getScrollX()' on a null object reference at android.app.ActivityTransitionCoordinator.setSharedElementState(ActivityTransitionCoordinator.java:435) at android.app.ActivityTransitionCoordinator.setSharedElementState(ActivityTransitionCoordinator.java:473) at android.app.EnterTransitionCoordinator.startSharedElementTransition(EnterTransitionCoordinator.java:332) at android.app.EnterTransitionCoordinator.access$200(EnterTransitionCoordinator.java:42) at android.app.EnterTransitionCoordinator$5$1.run(EnterTransitionCoordinator.java:389) at android.app.ActivityTransitionCoordinator.startTransition(ActivityTransitionCoordinator.java:698) at android.app.EnterTransitionCoordinator$5.onPreDraw(EnterTransitionCoordinator.java:386) at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:847) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1990) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1088) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5825) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:769) at android.view.Choreographer.doCallbacks(Choreographer.java:582) at android.view.Choreographer.doFrame(Choreographer.java:552) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:755) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5237) at java.lang.reflect.Method.invoke(Method.java) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707) 

Here is my code

  @Override public void getComments(String postId, String authorName, String message, String imageURL, String likesCount, RelativeLayout imageView) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && imageView != null) { ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(getActivity(), imageView, "revealLayout"); Intent commentIntent = new Intent(getActivity(), CommentsActivity.class); commentIntent.putExtra("postId", postId); commentIntent.putExtra("authorName", authorName); commentIntent.putExtra("message", message); commentIntent.putExtra("imageURL", imageURL); commentIntent.putExtra("likesCount", likesCount); startActivity(commentIntent, options.toBundle()); } else { Intent commentIntent = new Intent(getActivity(), CommentsActivity.class); commentIntent.putExtra("postId", postId); commentIntent.putExtra("authorName", authorName); commentIntent.putExtra("message", message); commentIntent.putExtra("imageURL", imageURL); commentIntent.putExtra("likesCount", likesCount); startActivity(commentIntent); } } 

I get the above data from adapter callback via interface

My XML:

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/root_layout" android:layout_width="match_parent" android:transitionName="revealLayout" android:layout_height="wrap_content" android:background="?android:attr/selectableItemBackground" android:orientation="vertical"> 

Same relative location with android:transitionName on the receiving side

This is my .xml style

  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">#c65643</item> <item name="colorAccent">@color/colorAccent</item> <item name="android:windowContentTransitions">true</item> <item name="android:windowSharedElementReenterTransition">@null</item> <item name="android:windowReenterTransition">@null</item> <item name="android:windowAllowReturnTransitionOverlap">false</item> </style> 

Also styles.xml (21)

  <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">#c65643</item> <item name="colorAccent">@color/colorAccent</item> <item name="android:windowContentTransitions">true</item> <item name="android:windowSharedElementReenterTransition">@null</item> <item name="android:windowReenterTransition">@null</item> <item name="android:windowAllowReturnTransitionOverlap">false</item> </style> 

Also went through this link https://code.google.com/p/android/issues/detail?id=224270&sort=-id&colspec=ID , but no luck

Thanks in advance

+6
source share
1 answer

Obviously, this is an Android bug in 5.0, and fixed in 5.1. Try setting a different ScaleType for the Transition ImageView, except for ScaleType.MATRIX .

ActivityTransitionCoordinator.java Source code for Android 5.0

 537 protected ArrayList<View> createSnapshots(Bundle state, Collection<String> names) { 538 ... 549 for (String name: names) { 550 Bundle sharedElementBundle = state.getBundle(name); 551 if (sharedElementBundle != null) { 552 ... 557 if (snapshot != null) { 558 setSharedElementState(snapshot, name, state, null, null, decorLoc); 559 } 560 snapshots.add(snapshot); 561 } 562 } 563 return snapshots; 564 } 

ActivityTransitionCoordinator.java Source code for Android 5.1

 629 protected ArrayList<View> createSnapshots(Bundle state, Collection<String> names) { 630 ... 641 Matrix tempMatrix = new Matrix(); 642 for (String name: names) { 643 Bundle sharedElementBundle = state.getBundle(name); 644 View snapshot = null; 645 if (sharedElementBundle != null) { 646 ... 650 if (snapshot != null) { 651 setSharedElementState(snapshot, name, state, tempMatrix, null, decorLoc); 652 } 653 } 655 snapshots.add(snapshot); 656 } 657 return snapshots; 658 } 

And the failure line in ActivityTransitionCoordinator.setSharedElementState

 376 private void setSharedElementState(View view, String name, Bundle transitionArgs, 377 Matrix tempMatrix, RectF tempRect, int[] decorLoc) { 378 Bundle sharedElementBundle = transitionArgs.getBundle(name); 379 if (sharedElementBundle == null) { 380 return; 381 } 382 383 if (view instanceof ImageView) { 384 int scaleTypeInt = sharedElementBundle.getInt(KEY_SCALE_TYPE, -1); 385 if (scaleTypeInt >= 0) { 386 ImageView imageView = (ImageView) view; 387 ImageView.ScaleType scaleType = SCALE_TYPE_VALUES[scaleTypeInt]; 388 imageView.setScaleType(scaleType); 389 if (scaleType == ImageView.ScaleType.MATRIX) { 390 float[] matrixValues = sharedElementBundle.getFloatArray(KEY_IMAGE_MATRIX); 391 tempMatrix.setValues(matrixValues); 392 imageView.setImageMatrix(tempMatrix); 393 } 394 } 395 } 396 ... 450 } 
0
source

All Articles