I am doing a very basic layout inflation of a XML layout into a linear layout container. The inflation is working however when I rotate the view that was inflated disappears (as expected) what I want to know is there a way to save the inflation or view group such as through on save instance state so that I do not need to inflate again since I read layout inflation is expensive!
You shouldn't worry about View inflations being expensive at orientation change! This is how Android works, on orientation change your Activity gets recreated. Period.
But if you really need to (you probably don't), it is possible to force an Activity to not get recreated, in short use android:configChanges="orientation" in your manifest activity declaration. More about this here.
Related
Let's say in an activity's xml it's using a LinearLayout as its root layout. And the activity during runtime wants to show a dialog/dialog fragment. Wouldn't the activity's xml have to be implicitly wrapped around with a FrameLayout for this to work due to needing to control the Z axis of views? Like you open the activity's xml and you see LinearLayout. However, behind the scenes, it's wrapped in a FrameLayout. Is this correct?
No, it's not.
It's complicated, and I'm honestly unable to properly explain it, but every Activity is placed in its own Window. Every Dialog attached to that Activity uses the Activity's Window to display itself.
I want to rearrange my views in onConfigurationChange when screen orientation changes. Activity restart and views recreation are too consuming; so I have to keep views.
There is one LinearLayout I want to change orientation of. If orientation is changed, I want to swap width and height values of all children elements. (In my case, they can be 0dp, wrap_content and match_parent.)
Of course, I can keep old orientation and iterate over children swapping their width and heights. But this task looks essential and not unique for me. Is there easier way to so that? Maybe it's already implemented somewhere?
It is implemented but only with activity restarts.
One method that doesn't involve iteration would be to recreate the View yourself with the landscape layout which is essentially what the Android system would do. The benefit though is you don't have to recreate the rest of your Activity. The downside is you have to unbind all your listeners that you've applied to your Views (onClickListener, onItemClickListener, etc). Not doing so would create a memory leak.
However, there is a simple method to doing this. Have your layout handled be a single Fragment style that only controls the Views. All clicks and user interaction is handled by this fragment that sends the actions back up to the Activity. When onConfigurationChange is called, simply remove this Fragment from the FragmentManager, then add a new Fragment.
I am working with CustomView which extends some Android view like FrameLayout. In my layout I use a ViewPager with a custom PagerAdapter.
The problem is that my View did not restore it's state when the fragment is re-attached to the ViewPager/Activity. For example, I have three fragments, if I swipe to the last one and come back to the first, the ScrollView is not where I let it : it's back to default, on top.
I know that with a PagerAdapter, not all fragment are active on the same time, basically juste the +1/-1.
I can't find why my View.onSaveInstanceState() is not called, so as onRestoreInstanceState.
The easy answer : it's because I was not setting id to my view (custom or not). Android didn't manage the onSaveInstanceState/onRestoreInstanceState if no id is set to the view.
So as my customView was extending base View, with not extra property, setting an ID to the view solved the issue and so onSaveInstanceState/onRestoreInstanceState are called as it should.
So to summary, use one of this approach :
from XML
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
...
android:id="#+id/scrollView">
</ScrollView>
OR from Java
yourCustomView.setId(R.id.myCustomView);
is last case, you add static id to res/values/ids.xml <item name="myCustomView" type="id"/>
Saving State by Default
We now have everything in place for our view to save and restore its state. However, this will not happen by default. If you want instances of your view to save state automatically, you can add this line to the init method:
setSaveEnabled(true);
Whether or not to do this is up to you. Even if your view does not save state by default, users of the view can always enable saving state by calling setSaveEnabled(true), or by specifying android:saveEnabled=“true” in the layout xml.
Is there a way in an Android Activity to do a setContentView(), so that I can have Android compute the layout, and so I can successfully get Views in it via findViewByID(), but not yet display it?
This would be in an app with a main activity and some subordinate activities and the one I want to start but not display would be one of the subordinate activities. (in other words the main view would already be filling up the screen, so it would be sufficient to simply keep the new one hidden at the bottom of the view hierarchy). The activity would be started with a "standard" launch mode.
If there's a way to do it by keeping it at the bottom of the View hierarchy, how would I force it to the top when I do want to display it?
NOTE: This app already exists - it's a large, complex industrial app with 14 Activities, written for Android 2.35 and 2.36, so re-architecting it to use Fragments instead of Activities would be impractical. I just want to modify one Activity to not display, or to just display at the bottom of the View hierarchy so it's not visible.
This would be in an app with a main activity and some subordinate activities and the one I want to start but not display would be one of the subordinate activities
That is not possible. Or, more accurately, you are welcome to start that activity and not populate its UI, but it will still take over the screen, and so the user will be presented with a blank screen, which is not especially useful.
in other words the main view would already be filling up the screen, so it would be sufficient to simply keep the new one hidden at the bottom of the view hierarchy
Each activity has its own view hierarchy. A "subordinate activity" cannot and will not be at the top, bottom, or anywhere else with respect to some other activity's view hierarchy.
Im quite new to Android but I think that this can bea easily done using fragments. One fragment will be the one that will be currently shown and the other will be overrlayed with a hiden parent view for an example. When you need to show the other fragment just set the layout to visible.
Hope it works, Good luck.
If you want to do this without using Fragments which I suggest you to use them you can use LayoutInflater to inflate whatever layout you like and change between them using setContentView repeatedly.
View layout1 = LayoutInflater.from(this).inflate(/*your first layout */ R.layout.activity_layout_1, getWindow().getDecorView());
//here you can use findViewByID like this
View someViewInLayout1 = layout1.findViewByID(R.id.some_view);
//... get fields for all others views you need here in layout1
//than you inflate your other layout
View layout2 = LayoutInflater.from(this).inflate(/*your second layout */ R.layout.activity_layout_2, getWindow().getDecorView());
//... do the same for layout2
Now you can call setContentView whenever you want to change between layouts.
setContentView(layout1 /*or layout2*/);
I am using fragments in combination with tabs to display some content. One of those fragments displays data that gets updated with an async task. Since I want to keep the content that was generated on configuration change, I set android:configChanges="orientation" in my manifest file.
This works just fine for the fragment.However, now I have got another problem: One of my other fragments uses a custom landscape layout. This landscape layout is not set on configuration change. I guess it is because I defined in my manifest to handle the configuration change.
Now, how can I force my fragment that uses the custom landscape layout to use the landscape layout on configuration change? What do I have to put in my onConfigurationChanged() method?
I haven't hit this situation myself, so I'm not sure (I've hit it with Activities, and the answer was to call setContentView again, then transfer over the data/state needed). But have you tried deattaching then reattaching the fragment, so it gets to recreate its view? Then you can re-inflate the view, which should inflate in the new mode.
If the differences are minor between the two layouts, another technique is to put both in 1 layout file and fiddle with visibilities on orientation change.