I\'m getting java.lang.StackOverflowErrors when my view hierarchy is being drawn:
at android.view.View.draw(View.java:6880)
at android.view.
Crazy idea 5 - May be not so crazy. I explain you the theory and you try implementing it some how. Lets say we have 3 nested views A > B > C. Instead of C be nested in B make it nested in D(some unrelated view) and when B will go to draw him self he need to call B.draw(). Of-course the problems you may run in to is bad layout. But it's possible to find solutions for that.
I would give this and this a shot, it will solve many of your questions and help you to further understand why a bigger stack is not really needed in the uithread. Hope it helps!
I don't know what the stack size limit is, and quite frankly I don't think searching that out is going to be of much use. As your second suggestion suggests, it could very possibly depend on what version of Android and/or the Dalvik VM is present on the device.
As for optimizing your layouts, some options include:
Use RelativeLayout instead of nesting ViewGroups, particularly LinearLayouts inside LinearLayouts, to help flatten your view hierarchy. This is not an all-purpose solution; in fact, nesting RelativeLayouts can hinder performance (because RelativeLayout always measure()
s twice, so nesting them has an exponential effect on the measure phase).
Use custom Views/ViewGroups, as per your fifth question. I've heard of several apps that do this, and I think even some of the Google apps do this.
<merge>
tag in some of your layouts (I myself haven't found many uses for them however)I believe that the main thread's stack is controlled by the JVM - in Android's case - Dalvik JVM. The relevant constant if I'm not mistaken is found in dalvik/vm/Thread.h
under #define kDefaultStackSize
Browsing for stack sizes through the dalvik source history:
API 3 (Android 1.5) = 8KB
API 4-10 (Android 1.6 - Android 2.3.7) = 12KB
API 14-17 (Android 4.0 - Android 4.2.2) = 16KB
So how many nested views can you have:
Impossible to say accurately. Assuming the stack sizes are as described above, it all depends on how many function calls you have in your deepest nesting (and how many variables each function takes, etc). It seems that the problematic area is when the views are being drawn, starting with android.view.ViewRoot.draw()
. Each view calls the draw of its children and it goes as deep as your deepest nesting.
I would perform empirical tests at least on the devices appearing in all the boundary groups above. It seems that using the emulator gives accurate results (although I've only compared the native x86 emulator to a real device).
Keep in mind that optimizations to how the actual widgets / layouts are implemented may also influence this. Having said that, I believe that most of the stack space is eaten by every layout hierarchy adding about 3 nested function calls: draw()
-> dispatchDraw()
-> drawChild()
and this design hasn't changed much from 2.3 - 4.2.
A better explanation of my crazy idea 5. I'm not saying it's a good idea :) but I wanted to clarify how it can be done.
We will create our own implementations for the basic layouts (LinearLayout, FrameLayout, RelativeLayout) and use them instead of the originals.
The new layouts will extend the original ones but override the draw()
function.
The original draw function calls dispatchDraw()
which calls drawChild()
- and only then you get to the draw()
of your child. This means the draw()
in each nesting adds 3 function calls. We will try to minimize it into 1 function call manually.
This is the disgusting part. Are you familiar with inline
functions? We theoretically try and make the calls to dispatchDraw()
and drawChild()
inline. Since java doesn't really support inline, the best way would be to manually make them inline (actually copy-paste the code inside into a single disgusting function).
Where does this get a bit complicated? The implementation we would take would come from Android sources. The problem is that these sources may have changed slightly between Android versions. So one would have to map these changes and make a set of switches in the code in order to behave exactly like in the original.
Seems too much work and it's one hell of a hack..