Scene transition with hero elements throws Layer exceeds max. dimensions supported by the GPU
Asked Answered
C

3

25

I am trying to do a hero transition in Android 5.0 between an image in a ListView to a details page. But for about 50% of my images Android crashes with the exception below. My images are 600x400 but I tried changing them to 200x100 but got the same error. When it works, it looks great but I cannot see the difference between the various images. Really unsure why it claims the layer is too big, anybody got a clue?

private void handleNewsItemClicked(AdapterView<?> arg0, View viewClicked, int arg2) {
    TopNewsItem item = ((TopNewsItem)arg0.getAdapter().getItem(arg2));
        Intent intent = new Intent(getActivity(), TopNewsDetailsActivity.class);
        intent.putExtra(TopNewsDetailsActivity.ARGS_ID, item.getGuid().getId());
        intent.putExtra(TopNewsDetailsActivity.ARGS_IMAGE,  imageUrl);
        if(Build.VERSION.SDK_INT >= 21) {                                 
            ActivityOptions options = ActivityOptions
                    .makeSceneTransitionAnimation(this.getActivity(),
                            viewClicked.findViewById(R.id.image), "article_image");                
            this.getActivity().startActivity(intent, options.toBundle());
        }else
            getActivity().startActivity(intent);
    }
}

W/OpenGLRenderer(18137): Layer exceeds max. dimensions supported by the GPU (1080x4628, max=4096x4096)
D/AndroidRuntime(18137): Shutting down VM
V/GAV3    (18137): Thread[main,5,main]: Tracking Exception: IllegalStateException (@MessageQueue:nativePollOnce:-2) {main}
/AndroidRuntime(18137): FATAL EXCEPTION: main
E/AndroidRuntime(18137): Process: myapp.app, PID: 18137
E/AndroidRuntime(18137): java.lang.IllegalStateException: Unable to create layer for  RelativeLayout
E/AndroidRuntime(18137):    at android.os.MessageQueue.nativePollOnce(Native Method)
E/AndroidRuntime(18137):    at android.os.MessageQueue.next(MessageQueue.java:143)
E/AndroidRuntime(18137):    at android.os.Looper.loop(Looper.java:122)
E/AndroidRuntime(18137):    at android.app.ActivityThread.main(ActivityThread.java:5221)
E/AndroidRuntime(18137):    at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(18137):    at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime(18137):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
E/AndroidRuntime(18137):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Crossruff answered 29/10, 2014 at 9:9 Comment(1)
FYI I reported this as a bug in Android: code.google.com/p/android/issues/…Luminosity
L
50

The Fade transition will use hardware layers when your view does has "hasOverlappingRendering()" return true. This was done for performance. You must have many views all fading out separately.

You have a couple options. One is for your views to have hasOverlappingRendering return false. This may not be possible in all cases, but it may be enough to solve your problem. Remember that this means that the contained views should not overlap!

The second is to transition fewer views separately. You can do this by setting android:transitionGroup="true" on ViewGroups that should be faded out together. For example, if you have a ListView with no background, you'll end up transitioning each element separately. Instead, you can set the ListView's transitionGroup property to true and then they'll transition together.

-- update --

The problem you're encountering is that the incoming Views that are fading in are too large. I tried the following View in the launching Activity:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:onClick="clicked"
    >
    <TextView
        android:id="@+id/hello_world"
        android:transitionName="hello"
        android:text="@string/hello_world"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

Yes, the hello world basic app from android, giving an id and transitionName to the text. The onClick handler just launches the second Activity, passing the hello world View as a shared element. The second Activity has an extremely large TextView, similar to yours:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:transitionGroup="true"
    >
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/hello_world"
            android:transitionName="hello"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="@string/hello_world" />
        <TextView
            android:layout_below="@+id/hello_world"
            android:text="Lorem ipsum.... I didn't copy all of my text"
            android:textSize="30sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            />
    </RelativeLayout>
</ScrollView>

Switching the ScrollView's transitionGroup from false (the default value) to true makes it work because then the ScrollView is being faded in. The ScrollView has a maximum size, while its contents can be enormous.

Lavish answered 29/10, 2014 at 19:15 Comment(18)
I tried the second option and it still crashed. I don't have many views, I only have the one imageview in the transition. Here is a video of the issue: youtube.com/watch?v=eq1ntnx7sJU. Can it be something else triggering this? I am loading the images with the Glide library in case that could affect anything.Crossruff
Nice app UI, BTW. I don't think the Glide library should be a problem. Now that I look at the error message a little better, I see that you're exceeding the maximum dimensions for a hardware layer. I have to think that the hardware layer it is trying to create is in the calling Activity (the list is growing, I assume). If this is caused by the Fade transition, you can remove it by setting the android:windowExitTransition to @null. You'll still see a cross-fade effect when the incoming activity comes up. You should also consider using a RecyclerView for that scrolling list.Lavish
Tried RecyclerView, same issue. So I changed to <item name="android:windowEnterTransition">@null</item> and everything works but the animation isn't very nice anymore. This seems like a bug to me? It is always the same image(s) that crashes, so if I restart the app it will crash the first time I click on that image. If I stick to the working images I can click 20 different articles without an issue.Crossruff
I misunderstood where the problem was coming in. If changing android:windowEnterTransition to null fixes the problem, then it is in the detailed page that the problem exists. The RecyclerView won't help in that case. One specific RelativeLayout cannot fade in -- its width is 4628. There is no way to fade such a large view with good performance on most phones, so this is something that you'll have to correct in your application. I suspect that you're doing a layout_width="wrap_content" and your content is very large. Try to find that RelativeLayout and tame it. :-)Lavish
I finally found the reason, it is the TextView with the article itself. Didn't really read the error message since it is the height that is the problem and not the width. That explains why some articles had issues and some worked fine. So how do I hack this together? Set the height to 1000dp and then set to wrap_content after the animation has finished or something like that? :-/Crossruff
I actually tried that and it worked using postDelayed, but then it crashed on the exit transition (since the textview is now too big). Should I give up the fade animation?Crossruff
You can know when your code is going to leave by overriding the Activity.finishAfterTransition call. Changing the height there will work, but it will also mess up your transition. If you've scrolled down into the article, it is going to show full screen and be centered on the text somewhere other than the top. You'll have to adjust the scroll position of the TextView to compensate. Something much easier to do is set transitionGroup="true" on the ScrollView/RecyclerView containing the article and the shared element.Lavish
Should I set the transitionGroup=true on the destination activity or only the source activity? I tried all the combinations I could think of without any success. Can the method described here work better maybe? ptrprograms.blogspot.no/2014/08/… Where the image is passed in the extras?Crossruff
I tried this: ptrprograms.blogspot.no/2014/08/… Where the image is passed in the extras and transitionGroup is set to false, and it crashed the same way.Crossruff
The problem is that the article is long, not that the image is large, right? I imagine that you have something like this in the detail activity: <ScrollView><Image><TextView></ScrollView>. If so, you want to set transitionGroup="true" on the ScrollView in the detail activity. I can write up a sample app to demonstrate.Lavish
I have no idea what transitionGroup does but it magically solved all the issues! I couldn't find that property documented anywhere? Really appreciate the help :-)Crossruff
Enter and exit transitions search for the views that are going to exit separately and tell them to enter or leave the scene individually. Typically this is a Fade transition, but you can use any Visibility transition. The Views that these transitions target are either non-ViewGroups or ViewGroups that have transitionGroup=true. ViewGroups default to true when they have a background. Fade is simple and you could do these all together, but Explode or Slide act on each View individually.Lavish
Thank you for this; I had the same issue and it fixed it. Conclusion: when you have a ScrollView containing potentially large elements like a TextView during an Activity Transition, you should always set its transitionGroup property to true.Vassaux
transitionGroup fixes it for me! Thank you!Luminosity
@GeorgeMount The issue is back in Android M :-/ #32071765Crossruff
@GeorgeMount If my Shared Element is contained within a viewgroup with transitionGroup=true, would this stop the sharedElement from animating separately from it's sibling views?Hotchpot
It shouldn't. The shared element should animate separately from its parent when transitionGroup=true. Some transitions make bitmap copies of their contents when transitioning. Those may include the shared element in their bitmap and you'll get a funny effect. In the case of Activity Transitions, I don't think any of the built-in transitions will have the problem.Lavish
This answer still saving people's asses, 2 years later. I also had a large TextView in a ScrollView!Linoel
P
8

The root cause of this issue is indicated in your log on this line:

W/OpenGLRenderer(18137): Layer exceeds max. dimensions supported by the GPU (1080x4628, max=4096x4096).

Your target activity has a height of 4628 which is greater than the maximum supported by the GPU - 4096.

The solution, already mentioned in the other answer, is to create a target activity which is shorter. Similar question and answer here: crash - material design android 5.0

Pepsin answered 17/1, 2015 at 3:40 Comment(1)
many thanks for your explanation. I'm getting Unable to create layer for RelativeLayout, size 768x7040 max size 8192 color type 4 has context 1 error, which confuses me because the reported height (7040) is smaller than the max size (8192). so why this error occurs?Errol
N
1

You can just avoid it if the fade transition isn't a must: see here for detail: https://mcmap.net/q/340276/-crash-material-design-android-5-0

Nomenclature answered 11/7, 2017 at 9:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.