I am learning fragments but I am failing to understand the significance behind why fragments requires a Container.
The way I understand Fragments work is as follows :
FragmentActivity setContentview refers to a xml file which
defines where fragments would be located.
FragmentActivity creates instance of the fragments
Then assigns fragment to container.
FragmentManager then displays them.
The actual Fragment class then inflates a layout, and it is this layout which
contains all of the applications UI components.
(please correct me if I miss something here because I am only learning at the moment).
So why is the purpose of the Container why do we even need since in all the examples I have seen it is just a blank relative layout xml document.
Can different fragments share the same Container (since its just a RelativeLayout xml file)?
So in the example provided by google http://developer.android.com/training/basics/fragments/creating.html
They have a ListFragment and when item is selected through the use of the CallBack interface we eventually get back to this line of code :
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
My other question is:
1) Why does this line of code not replace the ListFragment (left side Fragment) with the article fragment. Since when it was initialised we see:
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
Instead ... the ListFragment remains on the left and the right Fragment is updated.
But the container fragment_container belongs to firstFragment this is the ListFragment.
And this is not the one that gets updated.
Do you see why I have the question ? This is not explained in the tutorial.
Here: http://marakana.com/s/post/1250/android_fragments_tutorial
And here: http://developer.android.com/guide/components/fragments.html
Read this and all will be clear:)
Fragment is a portion of Activity and can exist only inside an Activity. So you need a special type of activity that can handle fragment - it's FragmentActivity.
FragmentActivity without Fragments is almost like a normal Activity. But it has a FragmentManager to manage (add,remove,replace) fragments. When you want to add a Fragment to a FragmetnActivity you should specify where it should be placed (because fragment does not need to be fullscreen, just like GooglePlay-there are multiple small fragments). So this is why you need a container.
Can different fragments share the same Container (since its just a RelativeLayout xml file)?
Yes they can, you can replace one fragment with another within the same container.
Related
Recently delve into fragments and from what I understand to create a fragment you need a java class and the fragments layout. This makes sense. However what I cant seem to wrap my head around is what "container", or layout do I use to store/insert the fragment? In android studio you can use this to insert fragments, or you can use any other of the layouts. But which one is ideal to use?
Also I saw in a reddit post that I shouldn't be using fragments at all and that its preferred to instead use Frame layouts and play around with your views visibility for the desired effects. Is this true?
You're slightly over-complicating the concept of Fragments.
Fragments, like Activities, don't actually need a dedicated fragments layout xml file. If you choose to do so, you can create the entire layout through Java code, not that I will understand why you'll choose to do so.
So for Fragments, you don't need a Java class and a fragment's layout file. The only requirement is the Java class, and the layouts file is just the preferred approach to inflating a layout, similar to how it is for Activities.
As for your question about the container of the fragments, it's really a matter of your app's design.
You can add a Fragment to your Activity or other Fragments, through the FragmentManager in code or through the <fragment> tag in your layout.xml files.
Neither of those are the best way or the preferred way, since it really depends on what your app needs.
Using the <fragment> tag will cause that fragment to always be added whenever the layout is inflated. This is actually VERY bad if your Activity requires dynamically switching Fragments due to your use of things like ViewPagers, Tabs, Drawer Navigation, or etc. However, it's GREAT if there's no need to dynamically switch fragments and for that specific Activity or parent Fragment, this fragment is a fragment that's always loaded.
For example, let's say you designed a flexible AddNew Fragment that's used in a Dialog and an AddNewActivity. Due to reusing the same screen and code, you decide to make this part of your code a fragment so you can insert it inside a DialogFragment or into another Activity. But, for those DialogFragments and Activities, the only Fragment it'll have is the AddNewFragment, so it'll make sense to just insert that fragment into the Dialog layout and Activity layout through the <fragment> tag.
As for the option with Java code, the preferred approach is to use a FrameLayout. But there's no need to play around with any View visibilities!
The common approach is to just use:
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
A FrameLayout is used because it's going to be the container of the Fragment. In other words, the Fragment will be stored inside of this layout.
So in Java code, you can simply use this code to replace the Fragment inside the container with your new one:
getSupportFragmentManager().beginTransaction().replace(R.id.container, AddNewFragment.newInstance()).commit();
Optionally, you can use add() instead of replace() if you want the fragment to be placed ontop of another fragment within the FrameLayout container.
So yes, to give a decisive answer to your question, there's no ideal way to add a Fragment to an Activity or another Fragment. Each option has it's benefits and drawbacks, with some working better for certain situations and others working better for others.
In the end, it really depends on what your App needs. If you need your Fragments to be flexible, so you can switch Fragments, then this must be done through Java code, because fragments added through the <fragment> tag can't be removed at runtime. However, if you don't need your Fragment to be replaced and it's definitely always going to be showing the same Fragment, then using the <fragment> tag removes the need to write extra Java code to load the dedicated Fragment.
One thing I really do need to point out is... that reddit page you read about is wrong. The 'preferred' way to use Fragments is not to use FrameLayouts and play around with View visibilities. I actually have no idea why there's even a need to change View visibilities.
You can use the new androidx.fragment.app.FragmentContainerView to get a better performance than FrameLayout.
Here more information.
You could use the Fragment layout, but this isn't very flexible. If you're just showing one Fragment, it should work, but using a FrameLayout and inserting your Fragment into it works better as this allows you to change them on the fly.
You may see a FrameLayout with the id R.id.container or something similar, and what this is used for is the Transaction.
For example, if you want to insert FragmentOne into your layout, you can just do this and it'll put it into R.id.container.
Fragment fragment = new FragmentOne();
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.container, fragment);
transaction.commit();
I've created an app, that has a main activity with a drawer menu so the user can click on some option and a fragment is open inside the activity.
What I'd like to do is to have several screens in one of the options and to navigate between them by tabs/slide the screen.
I saw an example of doing it inside one activity and with a fragment per 'sub-screen', my question is: how can I do it when I'm already 'inside' a fragment?
Thanks
Fragments can support having other Fragments inside them. The key to making this work is to remember to use getChildFragmentManager() to get the Fragment's FragmentManager instead of getFragmentManager() which gets the Activity's FragmentManager.
If you want to swipe between views, use a ViewPager inside your Fragment UI. The ViewPager will use a FragmentPagerAdapter to handle the Fragments for display.
I want to be able to replace the current fragment which is loaded via the actionbar tabs using a ViewPager with another fragment that is not connected to any tab like this
getSupportFragmentManager().beginTransaction()
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.replace(id,frag , "VideoEdit")
.commit();
however when I do this it loads the fragment all right but the tabs don't work anymore and everytime I click on a tab it just stays on this fragment. I managed to find this gist
https://gist.github.com/andreynovikov/4619215 but I'm not sure it's the same thing I'm looking for and I don't want to try it out for fear of messing up my existing code with it.
You should avoid transitions like that.
I'll recomend to use FragmentWrapper.
One more fragment that you placed inside Tab it contains only FrameLayout as a container for other fragments. In this fragment, you could use childFragmentManager to add current Fragment and replace it with VideoEdit.
What I already known is:
after fragmentTransaction.replace(), current fragment's onStop() function will be called
while fragmentTransaction.add() won't.
and after calling fragMgr.popBackStack();, we will return to previous fragment no matter fragmentTransaction.replace or fragmentTransaction.add() is used
So what does fragmentTransaction.replace do?
I can understand we can "add" a fragment opon a previous fragment and later return to previous fragment by popBackStack(), BUT:
if previous fragment is "replaced" by current fragment, I guess previous fragment is removed and current fragment is added in, how can it return to previous fragment when popBackStack() called?
You can add multiple fragments to a container and they will be layered one on top of the other. If your fragments have transparent backgrounds you will see this effect and will be able to interact with the multiple fragments at the same time.
This is what will happen if you use FragmentTransaction.add on a container. Your added fragment will be placed on top of your existing fragment.
If you use FragmentTransaction.replace(R.id.container,fragment) it will remove any fragments that are already in the container and add your new one to the same container.
You can also use the add method without a container id and your fragment will simply be added to the list of fragments in the FragmentManager and you can recall these at any time by their Tag value.
You can still return to a previous configuration IF you added the transaction to back stack. You can do this even if a previous operation removed a fragment. The removed fragment is remembered in the transaction and popping the back stack brings it back.
Two choices
Let's say you have a fragment container.
And, your task is to add a fragment into the container.
You can do this by calling any of the following methods
1) add(containerId,fragment)
2) replace(containerId,fragment)
But both methods differ in behavior !!!
Although both methods will add your fragment into the fragment container, their innards(internal working) differ based on the two possible states of the fragment container.
When fragment container
1) does not have any fragment in it.
2) already have one or multiple fragments attached to it.
Let's see what happens when we call add() and replace() method.
Case 1: When there is no fragment attached in a container
In this case, both methods will add the fragment to the container. So they will produce same effect.
Case 2: When the fragmentContainer already has fragment/fragments
add(): adds the new fragment on the top another fragment
replace(): removes everything then adds the new fragment
Example
So suppose the Fragment container has fragments[A->B->C].
Now you want to add a new fragment D.
add() method result will be [A->B->C->D]
replace() method result will be [D]
Relevant Link:
Check this Demo project for better understanding.
I'm having a bit of trouble implementing a design based around multiple ViewPagers.
At a high level, I have a FragmentActivity with just a FrameLayout as it's content. I have 3 different Fragments that I want to display. All 3 are full screen and only 1 will be used at a time.
Fragment 1 is a basic fragment with some TextViews and ImageViews.
Fragment 2 has a ViewPager and a FragmentPagerAdapter that feeds it several simple fragments.
Fragment 3 has a ViewPager and a FragmentPagerAdapter that feeds it several simple fragments (that are different from Fragment 2)
In my FragmentActivity onCreate() I get the FragmentManager and begin a transaction to replace whatever is in my FrameLayout with a new instance of Fragment 2.
At this point everything is working as expected. My ViewPager in Fragment 2 works perfectly.
Now I have a menu option that replaces the Fragment 2 in my FrameLayout with a new instance of Fragment 3. This also works fine.
The problem arises when I try to put Fragment 2 back into the FrameLayout with another replace transaction. I see my PagerIndicater at the top, but my pages are blank.
I've tried just creating a new instance of my Fragment 2 and calling a replace transaction. I've also tried setting a tag on my Fragments when I call replace and adding a findFragmentByTag check before my replace instead of creating a new instance. Both gave me the same result of blank pages after my second replace.
For reference
My first design was simply a FragmentActivity with a ViewPager and a ViewIndicater. I only had Fragment 2 and Fragment 3 from my description above and a menu option to switch between them. To switch I had 2 different FragmentPagerAdapters defined and just called ViewPager.setAdapter to set the selected FragmentPagerAdapter. This was working perfectly, but now I need a new top level Fragment that isn't using ViewPager at all. This is why I decided to move my ViewPagers out into their own Fragments. My idea being that I would just swap in my fragments to a FrameLayout.
I don't have my code in front of me right now so I can't post any, but I'll add some code to my question tomorrow to help facilitate answers.
This question is a possible duplicate of Navigating back to FragmentPagerAdapter -> fragments are empty.
If your app can handle it (API 17), use getChildFragmentManager(). This problem seems to occur when using a Fragment to host your ViewPager and using FragmentPagerAdapter. Changing to FragmentStatePagerAdapter seemed to fix the problem as well, but I still think using getChildFragmentManager() is the smartest thing to do.
brockoli you can used not "good way". But for my it's worked.
You can use in view 2 layouts, where you bind fragments. First - for fragment with fragments. Second - for other fragments.
On replace fragment with fragments do not replace, but only change visibility first layout to gone and add new fragment to second layout. On back, remove fragment from second layout and set visibility for first layout to visible.