I'm using tabs to switch pages in a container view. This works smoothly until I fill these pages with different kind of layouts or objects. The performance drops and it gets lower frames per second (no project butter here at all :D).
Can I use something else than fragments for this? Also if I want to keep the information (lets say I input my name on page 1) even when I have switched to another page?
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition( FragmentTransaction.TRANSIT_FRAGMENT_FADE );
transaction.replace( R.id.container, new FirstFragment() );
transaction.commit();
Each button in my tabsholder has its own fragment to change to.
What is making my performance drop? Is it not removing views? What should I use instead?
This is a rather wide question but I wouldn't know where to turn.
Related
When rotating the screen my nested fragment is shown but for some brief moments, the parent fragment is also shown.
I have my MainActivity that has a FrameLayout with ID activity_base_container.
I'm doing this when my activity starts:
Fragment initialFragment = getInitialFragment();
mFragmentManager.beginTransaction()
.add(R.id.activity_base_container, initialFragment, initialFragment.getClass().getSimpleName())
.commit();
That initialFragment initial fragment is responsible to check some conditions and depending them will launch one of two possible fragments:
fragmentManager.beginTransaction().replace(R.id.activity_base_container, fragment, fragment.getClass().getSimpleName()).commit();
Lets assume it launches FragmentF (whit a root FrameLayout with id fragment_f_root). This fragments layout has a set of options. When the user clicks one of those options, the corresponding fragment is created and is launched like this:
//The example here is an option that displays a google map.
fragment = FragmentMapMultipleActivity.newInstance();
fragmentManager.beginTransaction()
.replace(R.id.fragment_f_root, fragment)
.addToBackStack(fragment.getClass().getSimpleName())
.commit();
At this point all is working as expected. The problem is when I rotate the screen. FragmentF appears briefly and then immediately FragmentMapMultipleActivity, the nested fragment, appears.
Is it possible after rotating the screen show only the nested fragment or I should change my "architecture" to something else?
should change my "architecture" to something else?
Probably, you should.
The brightest Android-minds from Square are even advocating to avoid simple fragments everywhere it's possible: Advocating Against Android Fragments
Nested fragemnts, in its turn, increase complexity exponentially. The only good pattern of using them I've seen so far is ViewPager with it's FragmentPagerAdapter. In majority of other cases, consider using Custom Views instead.
It keeps your app's lifecycle cleaner and more predictable.
I don't think you can do much with this blinking you see, apart from:
setRetainInstance(true) and avoid full re-creation of the Fragment in Activity, so you keep you fragment's data during change of the configuration (and then pass same retained fragment to the fragment manager)
keeping layouts as lightweight as possible
avoid re-creation of already initialized variables
keep onViewCreate() as lightweight as possible
Good luck!
I'm using the Support Library and replacing a fragment with a custom slide-in animation.
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(enterIn, enterFragmentOut);
transaction.replace(R.id.content_frame, contentFragment);
transaction.commit();
The problem I'm experiencing is that the animation starts concurrently with the drawing of the fragment's views, and since the fragment has a rather complex layout (ListViews, &c) the animation is very stuttery (only a handful of frames are shown).
I've tried splitting the operation into two parts (with transaction1 = {add_new, hide}, transaction2 = {remove_old, show}) and firing the second transaction after onCreateView() has executed on the new fragment, but I didn't get much improvement at all.
What I'm looking for is a way to start the animation after the new fragment is fully drawn, if that's at all possible. Or any other tips that you may have on this issue...
Any ideas? Thanks a lot.
Im relatively new to android so im trying my hand at what i though would be an easy-ish app but I've ran into an issue to do with view/activity flow that i cant get an understanding on.
i have a fragmentActivity that uses a Viewpager to create tabs, each of those tabs is its own fragment class, thats all fine and working, but now i need to have one of the tabs display a list, when selected it takes you to another "view", my problem is how to create the first list and then how to handle tha clicking of an item in that list to take you to the new view so that the tabs stay in place and the back button doesn't exit the app.
currently ive swapped out the fragment with a list fragment that uses an arrayAdapter to build itself, this has worked as far as the list goes but i cant for the life of me figure out how to utelise its onclick() method to move on the the next screen, without as i said losing the tabs or having the back button simply exit.
so im not sure if A, the list fragment is the way to go, or B if it is how to move on to a new screen correctly
i can post code if needed but its a very general implementation of the classes mentioned so im not sure code will help
The callback you want to handle a click on an item in the list is onListItemClick.
As far as presenting a new screen, you can use a FragmentTransaction to replace your fragment with a new one, which gets a little hairy if you're doing this inside of a ViewPager. The code would look something like this:
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.some_containging_view, new SomeFragment())
.addToBackStack(null).commit();
Otherwise, you could simply launch a new Activity, which is simpler, but will mean that the tabs won't be present on the new screen unless you duplicate them there.
An elegant solution was finally found here, it uses a wrapper fragment around my list fragment so the pager is just concerned with the wrapper, meanwhile within the wrapper i can perform fragment transactions to my hearts desire, one small note the linked code uses getChildFragmentManager() that needs to be changed to regular fragmentmanager() from support.app for the backstack stuff to work.
TL;DR:
How should multi-pane apps with deep navigation similar to the Spotify iPad app look and work on Android, and how to implement this?
Long version:
I'm working on an app, where the user sees lists of items and can then delve deeper into these items. These item detail pages can again open lists of related items, that in turn have detail pages and so on. As a phone app, these would be separate Activities that might look and link to each other like this:
In the mock-ups, the user sees an initial overview and then selects "Item #2" from the first list. A new Activity opens up, showing him details for Item #2. Here, he selects to see a list of Things relating to Item #2. The newly openend Activity in the third picture shows this list, and clicking on one opens the details for this thing. He can navigate as deep into the content as he likes.
This works quite well with the usual Android Activities. I'm working on bringing the app to tablets and am thinking on how to best implement this. The plan is to create a multi-pane layout with the same concept. It is very similar to how the iPad Spotify app works (it will be interesting to see how they bring this to Android once they create tablet-specific layouts).
In the tablet layout, each click on an item or list name opens the corresponding child item as a new pane that animates in from the right. The same workflow as in the example above would look like this:
I'm unsure how to best implement this navigation pattern. Multi-pane apps with a limited navigational depth like GMail can be built with a static ViewGroup (LinearLayout would be ok) containing all fragments, and going deeper into the navigation replaces the content of the next container to the right and animates to this (see CommonWares implementation of this on SO).
This suggests that a custom ViewGroup would be the way to go. If it has to display a subpage (i.e. "List of Things"), then it creates a new child in the ViewGroup that is half as wide the screen with the fragment and then scrolls the visible area so that the pane that was just interacted with and the new child are visible. To link this correctly to a FragmentTransaction, so that the back stack works correctly, I'd guess it would be something like this:
View newPane = container.addChild();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(newPane, new ListOfThingsFragment(2));
ft.remove(paneOnRight, fragmentOnRight);
ft.commit();
container.animateToRight();
I don't see a way to do the animation within the FragmentTransaction.
Feedback welcome. My employer is generally favorable with respect to open sourcing frameworks we develop, so if this is something that is of broader interest and if I can come up with a reusable solution, I'd be glad to share it.
I had some research time and came up with a solution to this question (a question that I've wanted to see the solution for LONG time, even before you asked it).
I can't really show the whole code as there's some IP boundaries, but I'll put it here the main parts for this animation to works.
There're two key tools: setCustomAnimations and LayoutTransition
Yes, as far as I've been able to do it, you need to separate set animations to make it work.
So let's get to some code, you'll define your XML with a horizontal LinearLayout and make sure to include the following line on it.
android:animateLayoutChanges="true"
this will auto-generate a standard LayoutTransition which does translate the fragment/view that is staying in the layout and alpha (in or out) the fragment/view that is being included or removed from the layout. Give it a try.
So after this layout is inflated we gonna capture this LayoutTransition and trick it out to our needs:
LayoutTransition lt = myLinearLayout.getLayoutTransition();
lt.setAnimator(LayoutTransition.APPEARING, null);
lt.setAnimator(LayoutTransition.DISAPPEARING, null);
lt.setStartDelay(LayoutTransition.CHANGE_APPEARING, 0);
lt.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
with that code, we're removing the alpha animations and removing any delay from the transition (because we want all the translations to fire together).
And now it's just a few simple fragment transactions to make it work, during initialisation we inflate that layout and put a few fragments on it:
setContentView(R.layout.main); // the layout with that Linear Layout
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.main, frag1, FRAG_1_TAG); // it's good to have tags so you can find them later
ft.add(R.id.main, frag2, FRAG_2_TAG);
ft.add(R.id.main, frag3, FRAG_3_TAG);
ft.hide(frag3);
ft.commit();
now on the transaction it's a simple:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out, R.anim.push_right_in, R.anim.push_right_out);
Fragment left = getFragmentManager().findFragmentByTag(FRAG_1_TAG);
Fragment right = getFragmentManager().findFragmentByTag(FRAG_3_TAG);
ft.hide(left);
ft.show(right);
ft.addToBackStack(null);
ft.commit();
final notes:
to make deeper navigation it's just a matter of firing FragmentTransactions to add fragments to the LinearLayout and hide or detach the left side fragment.
Also to make the fragments work on the linear layout is important to set their LinearLayout.LayoutParams.weight during runtime, something similar to the following code applied to the fragment view
((LinearLayout.LayoutParams) view.getLayoutParams()).weight = 1;
to make it work on phones as well it's just a matter of applying the common multiple screen support patterns.
last note, be careful on proper managing the layout status during device rotation because it's not all automagically handled by the system.
Happy coding!
We ran into the same problem with our app. The constraints we gave ourselves:
Dynamic numbers of panes
Each pane can be differently sized
Fragments inside of panes must be correctly retained on orientation changes.
In light of those constraints, we built a new layout we call PanesLayout. You can check it out here:
https://github.com/cricklet/Android-PanesLibrary
It basically allows you to easily add any number of dynamically sized panes and attach fragments to those panes. Hope you find it useful! :)
Partial answer to the animation part:
You can do animations with the FragmentTransaction:
ft.setCustomAnimations(android.R.anim.slide_in_left,
android.R.anim.slide_out_right);
Update: see this answer from Reto Meier himself about fragment animation: https://stackoverflow.com/a/4819665/1007169
in my Activity, I have a layout containing 3 FrameLayouts, one at the top, one at the left and one at the "center".
Now, I sometimes only want to display one or two of them. Atm I am doing it this way:
FrameLayout frame = (FrameLayout) findViewById(R.id.framelayout_menu_left);
frame.setVisibility(...);
frame = (FrameLayout) findViewById(R.id.framelayout_content);
frame.setVisibility(...);
frame = (FrameLayout) findViewById(R.id.framelayout_menu_top);
frame.setVisibility(...);
However this can get really ugly results, e.g. when I switch the "content" Fragment and hide the top and/or left FrameLayout. It all starts flickering as the "content" Fragment jumps to the top and/or left and only afterwards is replaced.
Also, I can obviously not navigate back to another setup, so is there any other way to do this?
Kind regards,
jellyfish
Edit:
Maybe a little drawing makes my question clearer...
A shows a Layout of 3 FrameLayouts containing 3 different Fragments. Each color represents one distinct Fragment.
Now what I want to do is to switch from A to D.
I am doing this by replacing the blue Fragment with the yellow Fragment via a FragmentTransaction.
However, this still keeps the other Frames visible, so I hide them via the code above.
Now, Frame.setVisibility() is called way before commit(), so in B and C the blue Fragment "jumps" to the left and the top and only afterwards (in D) is replaced with the yellow Fragment. This produces a nasty flickering.
As a workaround, I now hide all three FrameLayouts before the transaction and re-show the ones I need once the transaction has finished. But there still is the problem that I can't go back via the back button as this isn't a real transaction.
I would have two suggestions. Firstly, if you both add a fragment transition effect and do the visibility changes after the transaction, that would probably substantially reduce much of your flicker effect
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
Secondly, I've simply given up on having the system manage the fragment stack for me -- it seems that this only works well with simple transactions. Override onBackPressed and do your own logic there.
--randy