Android: Increase call stack size - android

I have an application with very complex UI, containing many layouts nested one in another. While Creating another layout, I've caught a StackOverflowError
Wondering, I've created two test examples:
1) Hello world application with following xml for main Activity
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- ...So on 30 times... -->
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</FrameLayout>
<!-- ...So on 30 times... -->
</FrameLayout>
</FrameLayout>
</FrameLayout>
causes StackOverflowError while drawing the layout (cause every layout recursively draws it's children)
2) The following test case
public class TestOverflowActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overflow(0);
}
private void overflow(int i){
android.util.Log.i("Stack depth:", " = " + i);
overflow(i+1);
}
}
causes StackOverflowError on depth about 260-270 calls.
Every call of stack element for second test case takes 4 bytes for return address + 4 bytes for parameter = 8 bytes. It's possible that Dalvik's VM keeps a bit more info in every element, but even 16 bytes per element * 260 calls = about 4Kbytes for maximum overall stack size. This does not seem enough.
Is there any way to increase maximum stack size?

You might not be able to increase call stack size in the main UI Thread(which is understandable because you're supposed to do as few things as possible here), but you can do it in a separate thread by making use of the Thread object's constructor parameters:
ThreadGroup group = new ThreadGroup("threadGroup");
new Thread(group, runnableObject, "YourThreadName", 2000000).start();
With this example I increased my stack size from 8k (around 260 calls) to 2M (enough for not to get the StackOverFlowException, of course you can add as much as you want as long as the memory can take it), so in the end, for further readers, this is the way you can increase your stack size,although is not recommended, in some cases it's actually necessary for example an algorithm with extensive recursive calls and of course by doing all the hard work in a worker thread(as you're supposed to) with your specified stack size and just "posting" changes in UIs using the main UI Thread with Handlers or whatever mechanism you would like to use to interact with it...
Hope this Helps...
Regards!

You definitely don't want to nest layouts inside each other like that. If you find yourself nesting three or four times then the construction of the view becomes less and less efficient, which can cause activity transitions to start and probably in your case finish before the view is created. Which will look weird, or be a complete waste of an activity transition.
You should make your root layout a relative layout and have all your frame layouts as children of that root relative layout.

If you need this complex layout (as many will doubt) you can still draw it programticaly in onCreate method.

Related

Android: how can I add different layer to a image view dynamically?

I have one fragment layout with a background image. Programmatically I have to add the different layer to this image because I want to add some particular details depending of some data. There are three different details that it can change in 3 different way. ( there is a thread that works at 5/10hz and it loads the right details)
The following is my first implementation. In this version, I have done all of works in XML layout and in a programmatically way, when the user clicks on a certain button, I set the visibility of each image view. I have seen that is much expensive, and sometimes the inflate layout return null:
<RelativeLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/background"
>
<ImageView
android:id="#+id/layer1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ballgreen"/>
<ImageView
android:id="#+id/layer2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ballred"/>
<ImageView
android:id="#+id/layer3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:src="#drawable/ballyellow"/>
... 6 more image view layer....
</RelativeLayout>
Then I thought to use an async task to decode all drawable image, make a bitmap fusion and in a post execute load the result bitmap in a single image view.
But the asynctask is not the better way to implement, because the user can click on that button many times and each time I have to call new asynctask ..
Are there a clever ways to implement all of this?
Goodbye and thanks a lot :)
EDIT : each layer is a detail that thread can add to that image.
For example : a car, a tree, a red ball ecc ecc. In the xml example for me each imageview is a layer, and this is wrong. But I don't know the clever way to implement ..
EDIT2 : Moreover I know the maximum amount of layer, but there are many combinations. there are 3 point and for each point I can choice between 3 differents details
Edit3: i add some details , there is a thread that change laYer and not the user
Use the LayerDrawable class, adding new layers as the user enables them. I don't think you can remove layers from it, but you can create a new LayerDrawable each time the user disables a layer. Or you can use setDrawable(int, Drawable) to replace a layer.
This means you don't have to complicate your layouts, and should get rid of those pesky extra inflation/measure/layout passes.
As for the image loading / async task stuff: use an LRU cache for your bitmaps. When a layer is enabled, check the cache, and if it's there, just use it. Otherwise, use an async task to load it.

Preview ViewSwitcher in AndroidStudio

Is there an easy way to switch between the displayed view in a ViewSwitcher in the Android Studio preview, or is the only way to swap out the XML for the sub-views one at a time?
Unfortunately, there are no XML attributes or any option on Android Studio which can help you to define the displayed view.
A similar question for the ViewFlipper was asked here (they both are direct subclasses of ViewAnimator).
However, if and only if your views are large as the screen, you could use the include tag, for example:
<ViewSwitcher
android:id="#+id/myViewSwitcher"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/first_view">
</include>
<include
layout="#layout/second_view">
</include>
</ViewSwitcher>
Then you can see your layouts in a separate XML file.
First of all if you are thinking to use ViewSwitcher, just for showing ProgressDialog then you are not doing it in a way in which it should be.
ViewSwitcher generally used to change layout of Activity. In your case ProgressDialog is not a View of your Activity rather it is just small helper which indicates some process is doing. So In short ViewSwitcher should be use somewhere where you want to alter complete screen of Activity.
In your case you can divide your layout into smaller layout files and group them using merge or include.
Create separate files for all different screens which will define UI of your Activity and group them using include.
For an example we can create small App for Introduction thing using ViewSwitcher -
First Screen - my_product.xml - this layout will define something about product.
Second Screen - about_us.xml - this layout will describe about your company.
Third Screen - thank_you.xml - to say thank you to your users.
Group them in any container View.
<ViewSwitcher
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
layout="#layout/my_product"/>
<include
layout="#layout/about_us"/>
<include
layout="#layout/thank_you"/>
</ViewSwitcher>
ViewPager can easily solve your issues.
ViewPager (it can hold multiple views). ViewPager is kind of Array Container for View objects. You can have ViewPager rotation (like you do the array rotation) or other techniques to swap inside views. And, you can create your each inside views based on the Factory DP, so that there happens less processing (shares common resources).
They have mentioned swiping views here (Note: you just need own view swiping techniques if you don't want to use default ViewPager rotation).
Creating swipes: https://developer.android.com/training/implementing-navigation/lateral.html
ViewPager for screen slides: https://developer.android.com/training/animation/screen-slide.html

Image will not display in contentview

In Xamarin, I have a simple Activity that loads up with a five second wait before another Activity is loaded.
The first Activity has an image as part of the Layout, yet this image is not being displayed.
Here is my Activity code:
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.SplashActivity);
Thread.Sleep(5000);
var testActivity = new Intent (this, typeof(TestStartup));
StartActivity (testActivity);
}
Here is my SplashActivity layout code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/background_color">
<ImageView
android:src="#drawable/Splash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/SplashImage"
android:layout_gravity="center_vertical" />
</LinearLayout>
The application waits five seconds, and then the TestStartup Activity loads, however, the image is not displayed during the five second wait. How can I display this image while the Activity waits five seconds?
Can I please have some help with this code?
Thanks in advance
It is not shown because you are blocking the UI Thread with
Thread.Sleep(5000);
You should get rid of this kind of logic. Relying on x secs it is always wrong. The computation you are waiting for could be ready before, making the remaining waiting period a wast, or could require more the x secs. To "fix" your issue you can use Handler.postDelayed(Runnable, 5000), and put the logic you need to be executed inside the run method. This way, at least, the UI Thread will not be blocked
You might want to take a look at Xamarin's tutorial for creating splash screens in Android:
http://developer.xamarin.com/guides/android/user_interface/creating_a_splash_screen/
It looks like you were on the right track, but they use a theme rather than setting the content view. As previously mentioned, your layout isn't being displayed because your sleep method is blocking the UI Thread. Using a theme is a good way to get around this, and you can reuse a lot of what you already have.

Issue regarding include tag in xml and implementation of the views

Hi all and thank you in advance and sorry for my english. I have two big doubts
1 - I haven't been too much time programming in android, and i pretty sure there is a lot of things i have made in wrong ways. For example, I have made several apps where in xml definition i include another xml.
For example, imagine 2 activities with a header_section.xml being include in both activities xml definition. That header_section has 5 buttons and more views etc. Ok, in the xml is just make an include and it works......but to implement the buttons.....do i have to REPEAT the code in both activities?? it sounds really bad practice to duplicate code in both activities.....but how can i do, for example this in activities A and B? Do i have to put this code exactly the same in both activities classes????
private View header_section;
private Button bExample;
header_section=findViewById(R.id.header_section);
bExample=(Button)header_section.findViewById(R.id.bExample);
bExample.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Whatwever...call a number, for example
}
});
In main xml something like:
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="0dp" >
<include android:id="#+id/header_section" android:layout_gravity="center" android:gravity="center" layout="#layout/header_section" />
</LinearLayout>
and in header_section.xml something like:
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="0dp" >
<Button android:id="#+id/bExample" />
</LinearLayout>
2 - Imagine you have like 10 activities in your app. If in all of them there are a header section and bottom section with the same functionality, changing just the central area (showing different lists, views etc)......is better have just one activitie in ALL the app, with a viewflipper in the central area? or have 10 activities having, i do not know if can be avoided, asked in point 1, code repeated in all 10 activities for the implementation of the headers and bottoms views, handlers etc?
Thanks and best regards
1) Yes, usually, you should have to use them BUT you can make it simplier...
1.a) bExample=(Button)findViewById(R.id.bExample); //don't need to load the View
1.b) You can shorten a bit how you call the onclick, in your button/clicable element inside the LAYOUT, here's an example:
<!--inside layout -->
<Button android:id="#+id/bExample" android:onClick="aceptar" />
and
//inside the Activity
public void aceptar(View v){
//here the code of the button
}
For the question about implementing the same methods inside all Activities, check this post: Adding the same context menu to multiple activities
2) Depending the application
If you don't do much, you can load all in the same activity and HIDE/SHOW the layout elements you don't want.
But it's better to use different activities, anyway, if the layout is not "heavy" (too many elements/includes inside) you can load the SAME layout for all your activites, and you only need to change the different contents (strings) and/or HIDE/SHOW the different elements.

Complex Android UI design guidance needed (fragments)

I am developing an applications that is aimed at Tablets and Google TVs. It will be like many standard Google TV applications with a LeftNavBar and a top Search bar that is common to all application screens. It will look something like the following image:
Main Screen
The RED area will be different for all other screens. It may contain data like following screens mockups:
Activity One loaded into main container
Activity Two loaded into main container
So you can see that completely different sections can be loaded in the main area.
Screen 3 can be loaded as a detailed section when selecting any list item in Screen 2 (say in fragment list) OR it can be loaded as a result of selecting a tab (which will appear in LeftNavBar).
Here is how I am trying to implement it.
Step 1. I Created a main Activity with the following XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#9ccc" >
<!-- Top Bar -->
</LinearLayout>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<!-- main Red Container that will load other Activities -->
</FrameLayout>
</LinearLayout>
mainContainer is the RED container where I want to load the Activities. LeftNavBar will be added to this Activity as its the parent of All.
Step 2 I created ActivityOne & ActivityTwo with two & three Fragments in them respectively (as shown in above second & third image).
*Step 3 I am trying to load the ActivityOne in main page's mainContainer FrameLayout... But I cannot add it.
I tried by adding the ActivityOne to mainContainer as follows:
View v = (new ActivityOne()).getWindow().getDecorView();
FrameLayout mainContainer = (FrameLayout) findViewById(R.id.mainContainer);
mainContainer.addView(v);
but the getWindow() returns null....
Other issue occurs because all the data comes from a remote services .. so please also suggest how would I be able to hold references to all the loaded Activities in mainContainer in a some kind of stack ... so I can just reload the already loaded activity instead of creating its new instance.. This will be used on BACK button press.
OR
Instead of loading an activity into the above RED container, I should create two Activities each with their own Fragments & a LeftNavBar. This might be easier than the aforementioned approach. or this might be the only solution.... however I feel that saving state for BACK buttons might get messy .. but I will try implementing this
What would you do if you had to create this type of application?
How would you design the UI layout for best performance/practice?
Your suggestions in helping me setting this app's layout are much appreciated.
Disclaimer
This is where fragments can get tricky. The problem would be simple if Activity 1 & 2 had identical layouts so that you could simply attach/detach fragments and use the fragment back stack to unwind.
Because you want 2 unique layouts to house your fragments, things are going to be a little more involved. If at all possible I would try to use the same layout so that you can take the easy path.
As another option, you could use two activities as you outline above and send data back and forth with Intents.
That said, if I really had to implement this solution as written, here is what I would do. Note that I am not advocating this solution but myself do not know of a better way of doing things.
The Solution
Create a FragmentActivity whose view would be Main Screen as you've defined above. The layout for the Main Screen would contain:
Left nav bar
Top bar
2 layouts. layout1 and layout2. These would be contained in a parent layout i.e. RelativeLayout or LinearLayout and would contain the necessary FrameLayout elements for your fragments.
Example using your XML (note, tags are a bit brief):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#9ccc" >
<!-- Top Bar -->
</LinearLayout>
<LinearLayout android:id="#+id/layout1">
<FrameLayout android:id="#+id/listFragment" />
<FrameLayout android:id="#+id/contentFragment" />
</LinearLayout>
<LinearLayout android:id="#+id/layout2">
<FrameLayout android:id="#+id/imageFragment" />
<FrameLayout android:id="#+id/boxFragment1" />
<FrameLayout android:id="#+id/boxFragment2" />
<FrameLayout android:id="#+id/boxFragment3" />
</LinearLayout>
</LinearLayout>
The main idea is that you then show/hide layout1 & layout2 i.e. set android:visibility="gone" based on the state of your app.
The disadvantages of this method are:
Using fragment backstack may be impossible, instead you'll have to track where the user is in your UI flow and manage the back button to show/hide layout
You may need to take special care to attach/detach fragments when you show/hide their parent view to reduce resource consumption while the fragments are invisible
The advantages are:
Easy communication between fragments and the base activity since only 1 activity is used
Re: The nested Fragments problem
To get around the 'nested Fragments' problem in our application where (as you correctly note) Fragments cannot add Fragments I hosted a single templating Fragment under the activity whose only purpose was to define a set of place holders for other fragments to anchor to. When adding further Fragments to the activity past this point I used the templating Fragment's view place holder +#ids to identify the "root" or parent view Id for the Fragment being added.
getSupportFragmentManager().beginTransaction().add(#someIdFromTheTemplateFrag, fragment, fragmentTag).commit();
The Fragment I was adding then knew where to anchor itself in the current layout and of course then went about it's merry way of add it's view. This had the effect of attaching a Fragment to another Fragment hence achieving the desired visual 'nesting'...

Categories

Resources