Prototik / HoloEverywhere

NO LONGER MAINTAINED. DEVELOP FOR 4.X+ DUDE.
MIT License
2.18k stars 608 forks source link

StackOverflowError for using too many nested views #481

Open appixia opened 11 years ago

appixia commented 11 years ago

I have an app that looks like the Google Play store app. Every tab is a nested fragment inside a fragment view pager (using v4 support and HoloEverywhere).

This modular design (using fragments for tabs) is very convenient to work with, but is somewhat wasteful on view hierarchy - creates too many nested views. I've attached my current hierarchy from Hierarchy Viewer below.

Everything runs fine on Android 4+, but when I run on Android 2.3 I'm getting a StackOverflowError when the layout is drawn: at android.view.View.draw(View.java:6880) at android.view.ViewGroup.drawChild(ViewGroup.java:1646) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) at android.view.View.draw(View.java:6883) at android.view.ViewGroup.drawChild(ViewGroup.java:1646) at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) ...

After some research, I've understood that I simply have too many nested views and older Android OS's allocate a very small stack for the UI thread (about 8KB) which is enough for about 60-100 stack frames - which is simply not enough for my modern layout..

I've posted a question on stackoverflow.com and found similar questions too: http://stackoverflow.com/questions/16843357/what-is-the-android-ui-thread-stack-size-limit-and-how-to-overcome-it http://stackoverflow.com/questions/2762924/java-lang-stackoverflow-error-suspected-too-many-views http://stackoverflow.com/questions/6705425/fixing-the-stackoverflow-error

The general answer to fix this seems to be to stop using fragments and simplify my layout.. but this defeats the purpose of the entire HoloEverywhere library. I want the nice modular design fragments provide, and I want the nice UI on older versions of the OS.

This means I need to find a different answer. So my question is this:

  1. Do you have any good ideas that will let me keep my fragments and nice design?
  2. This problem is essentially a design problem with Android OS. Someone messed up and made the UI thread stack tiny. The closest thing I found to a real solution for this problem is this: http://stackoverflow.com/a/14885190/1025458 . What do you say about this? maybe it should be incorporated out-of-the-box inside the HoloEverywhere code?

My current view hierarchy promised earlier: hierarchyviewer

Prototik commented 11 years ago

Only one thing i can help - open android.support.v4.app._HoloFragment and modify method public final View onCreateView(android.view.LayoutInflater, ViewGroup, Bundle like this:

    @Override
    public final View onCreateView(android.view.LayoutInflater inflater,
            ViewGroup container, Bundle savedInstanceState) {
        return onCreateView(getLayoutInflater(), decorView, savedInstanceState);
    }

This remove ContextMenuDecorView from all fragments. 3-4 levels of depth.

Not HoloEverywhere problem.

appixia commented 11 years ago

There are 2 main problems:

  1. The basic app with a ViewPager takes a minimum of 5 nested views (mostly due to ABS and support lib)
  2. Every fragment takes a min of 3 views (mostly due to ABS and support lib), since I use nested fragments I get an extra of 6 nested views

The stack size of UI thread in Android 2.x is 12KB and in Android 4.x is 16KB. These 4KB make all the difference - since the above layout crashes on 2.x with StackOverflow.

My current solution was to stop using fragments altogether (this saved me 5 views total). So right now instead of a fragment I'm just adding ViewGroups manually. Kinda sucks that I can't use fragments, but they are too wasteful on views until we fix this some how.

Prototik commented 11 years ago

I can only try to merge NoSaveStateFrameLayout and ContextMenuDecorView, but it's hardly.

appixia commented 11 years ago

@Prototik I think we should consider helping with this issue although obviously it isn't a holoeverywhere problem. The point of holoeverywhere is to support older (2.x) devices. If supporting them fails due to stack overflows, and we can somehow help it will really contribute to the value holoeverywhere gives programmers.

appixia commented 11 years ago

I had some crazy idea to create my own UI thread with a larger stack size. Do you think it's possible? It will be difficult since there is no documented way to do it, but it will solve the problem at the core

Prototik commented 11 years ago

Ma... Maybe. I keep this issue opened. JRE: -Xss100500Mb Android: Fuuuuck. Again multiplue parts of undocumented api with different level of operability. VMRuntime should work on pre gingerbread devices. But on Ginger VMRuntime is broken...

appixia commented 11 years ago

Thanks for keeping the issue open! I'll experiment with creating a larger UI stack manually - already posted a stackoverflow question about it to get ideas: http://stackoverflow.com/questions/16913317/create-the-ui-thread-manually-in-android-in-order-to-increase-its-small-stack-si

I've also researched and found in dalvik/vm/Thread.h source that the default stack size was increased from 12KB to 16KB in Android 4.x, so they know there's a problem there. On Android 1.5 it was 8KB, simply ridiculous

tkiela commented 11 years ago

Hey there, cause I am handling the same problem mentioned here, I am also looking for any solutions.

What do we remove with the "ContextMenuDecorView"? For what is this view used?

Prototik commented 11 years ago

@tkiela for handling a context menu into fragments. Code for removing a CMDV from fragments see above. Also you can remove WindowDecorView (ActivityDecorView into latest snapshot) from activity, then you lose support activity with dialog theme and again support of context menu.

appixia commented 11 years ago

@tkiela Removing the ContextMenuDecorView wasn't enough for me because I had a lot of nested views. I ended up not using fragments anymore at all. I'm still using HoloEverywhere but I replaced all fragments with manual ViewGroups. This means I'm adding, animating and removing ViewGroups manually. It behaves just like fragments, but I have full control on exactly how many views I have