Attach a fragment to an activity in Android - android

My older version of an Android app was using 4 different activities (FirstActivity => FourthActivity, with the corresponding xml activity_first => activity_fourth), and the app can switch back and forth between those using Intent. Recently I wanted to change the user interface to use a ViewPagerIndicator. I have implemented 4 fragments like this:
public class FirstFragment extends Fragment{
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
return inflater.inflate(R.layout.activity_first, null);
}
}
The question is, how can I migrate all the business code from FirstActivity to FirstFragment? Do I just need to find the equivalents of onCreate, onDestroy, onStart... and copy/paste the code (adding getActivity(), getView() where appropriate)? Is there any easy way to attach the fragment to an activity to avoid doing so?

The easiest way to do it is to migrate the code you had in your individual activities under onCreate() to onActivityCreated() in the new fragments. You then add the fragments to your activity using a fragment transaction in the onCreate() method of your supporting activity. The android docs give a pretty good walk through of how to do this here, complete with sample code. In case there's some confusion you're going to do the following in your underlying activity:
Get a new FragmentManager
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Create a new instance of your fragment
ExampleFragment fragment = new ExampleFragment();
Add that fragment to your FragmentManager
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
There are a number of different ways to use fragments - like in a ViewPager or ViewSwitcher that require a different implemenation but this sounds like it address what you're trying to do.

Related

How to get current fragment from MainActivity

I've done some research but I really couldn't find the answer.
I have single activity with side menu, and holder. I have many (non support) fragments, and all of them are using same holder (one at a time).
When user uses menu (it's in main activity), and goes another page, I want to add name of the current fragment to backstack (using .addToBackStack(Fragment1.class.getName())), but I couldn't find how to get current fragment.
I don't want to implement interface etc to keep track of current fragment. There is a super simple way using fragmentManger isn't there?
You can get your current fragment like this:
if (getFragmentManager().getBackStackEntryCount() > 1) {
Fragment f = getFragmentManager().findFragmentById(R.id.content_frame);
if (f instanceof BlankFragment) {
// Do something
}
}
OK,
If you want to get latest entry from backstack(thanks to #AndroidGeek);
fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-1);
and, if you want to get currently active fragment (thanks to #Salman500 #AndroidGeek);
Fragment f = getFragmentManager().findFragmentById(R.id.fragment_holder);
you can use this to get fragment id for non support fragment
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_id);
if(fragment!=null)
{
getFragmentManager()
.beginTransaction()
.addToBackStack(null)
.commit();
}
You can keep track of fragments in the main activity (with variables) and access them there. Example:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction= manager.beginTransaction();
MyFragment myFragment = new MyFragment();
myFragment.doSomething();
Adding to the back-stack:
FragmentTransaction fragment = getSupportFragmentManager().beginTransaction();
fragment.addToBackStack(fragment);
fragment.commit();
This is answered here: get currently displayed fragment
Just use addToBackStack() before you commit() the fragment trancsaction. See it here
So your code will look like :
...
fragmentTransaction.replace(R.id.holder, newFragmentToShow, newFragmentTag);
fragmentTransaction.addToBackStack();
fragmentTransaction.commit();
...
EDIT : after OP was edited
You do not need the fragment class to call addToBackStack() as you have mentioned in the OP. The String argument is an optional string just to keep the state for the backstack state. You should see the documentation
It is all internally managed and the current active fragment is automatically added to the backStack, you may call it from where ever you want, it will always use current active fragment.

FragmentTransaction 'add' not working

I am having problems adding a fragment to a frame layout placeholder:
TestDialogFragment newFragment = new TestDialogFragment();
int id = R.id.fragment_placeholder; //id of the FrameLayout placeholder for the TestDialogFragment
getFragmentManager().beginTransaction().add(id, newFragment, "testdialogfragment").commit();
I have breakpoints in the onAttach and onCreate methods in TestDialogFragment and they don't get hit, which goes against what I read in the android fragment API Guide. Is there something I'm doing wrong with the add transaction above?
P.S. TestDialogFragment extends Fragment
I fixed this by setting & getting arguments with Bundles instead of interacting directly with the fragment via its public methods after committing the transaction. My mistake was assuming that the fragment was up and ready to use (attached, layout inflated etc) as soon as the commit() statement was finished.

Android activity and fragments

I've setup a new Android project that comes with an activity. Here's the boiler plate code:
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment())
.commit();
}
Can someone explain what this is doing exactly? From what I can see, it checks if the activity hasn't been initliazed and then inflates the layout. But what I don't understand is beginTransaction(), ew PlaceholderFragment(), and commit()
Thanks.
You use fragment transactions to add / replace (etc) fragments within a FrameLayout (R.id.container) and new PlaceholderFragment is a new instance of a fragment to be put into the container
//Check whether we're recreating a previously destroyed instance
if (savedInstanceState == null) {
//Execute a transaction, replacing any existing fragment with this one inside the frame.
//Getting FragmentManager object which will control fragment acvitiy
FragmentManager fm = getFragmentManager()
//Starting a FragmentTransaction which will handle transaction to this fragment activity
FragmentTransaction ft = fragmentManager.beginTransaction();
//Add a fragment to the activity state. This fragment may optionally also have its view (if Fragment.onCreateView returns non-null) into a container view of the activity.
ft.add(R.id.container, new PlaceholderFragment());
//Schedules a commit of this transaction.
ft.commit();
}
There is a good explanation to fragment activity here, here and here
FragmentManager is a class which helps in managing the fragments that an activity may need. So here you are basically getting an instance of it and you are beginning a transaction. You need an instance of transaction because it lets the runtime know that some change is going to happen when this is called. Here 'add()' is that change and finally you commit it to save that change.
The arguments to add are the layout where the fragment needs to be added and the PlaceHolderFragment() is the name of the Fragment you need to put in.
As fragments are the way to go, replacing all of many heavy Activites, Eclipse has also adapted to this change which cause the boiler alert. :)
Starting a fragment (which cant be done via Intents) is treated as a transaction just like in database (not a good example i guess).
getFragmentManager() - gets the Activities FragmentManger which is responsible to initiate FragmentTransaction.
beginTransaction() - creates a new Transaction for this particular fragment job.
new PlaceholderFragment() - is an instance of the PlaceholderFragment which you can find if scroll more in the Activity.
commit - a way to commit this trasaction and bring it to effect.
See Android docs. for more details. :)
It is simple my friend.
In simple Coding Language:
if (savedInstanceState == null) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.tab5, new PlaceholderFragment());
fragmentTransaction.commit();
}
If you think that it explain everything, then it is a pleasure for me. Otherwise just ping me to add theory information.

Fragments layout on Android studio

I am adding layouts to my Project and each time I add a layout it also add another layout that comes with the Word "fragment"... can somebody explain me for what is for? I had look over the web and it explain other kind of fragments...
Android Studio, when asked to create an Activity, will create 4 things for you :
An Activity class
a layout file for the Activity class, which will include a FrameLayout serving as the container to place the fragment
a Fragment class (created as an innner class inside your Activity)
a layout file for your fragment (this is the second layout you see in
your project structure), say for example fragment_test.xml
If you look closely, you Activity code will contain something like this :
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_test, container, false);
return rootView;
}
}
My guess it that this was done so it guides developers to use fragments for the screen's actual content rather than placing it inside the Activity's layout itself. The Fragment is designed to be a re-usable component, so if you have several layouts for your activity depending on the screen size/orientation, you can re-use the same fragments, just placing them differently inside your Activity layout, which is an excellent practice.
I hope I clarified things a bit ;)
This is an Android 0.8 question, using the Activity with Fragment template.
So, how would you go about swapping one fragment in for a second fragment? in the same Frame? Perhaps for a button click, for example.
Use case, might be a "connect the dots" questionnaire where the next button goes to the next fragment.
I understand that the answer is FragmentManager and FragmentTransactions.
When I do this from with in a click event,
FragmentManager FM = getFragmentManager();
FragmentTransaction FT = FM.beginTransaction();
FT.replace(R.id.container, new FRAG02());
FT.addToBackStack(null);
FT.commit();
I get an error:
must implement OnFragmentInteractionListener
It would seem that there is a SOP way of replacing fragments that I am not aware of. Seems like a related comment.

Dynamically added fragments are not removed when the container is removed

I am trying to understand a bad behaviour in fragments: the onCreateView and onActivityCreated methods are called even the fragment is not 'visible' in the layout.
If you use the code:
TestFragment testFragment = new TestFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragmentDetail, testFragment, "test");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
replacing the FrameLayout with id fragmentDetail with the fragment and then you rotate the device, the fragments method are still invoked even if the container is not present anymore in the portrait layout. This doesn't happen if you use the 'static' <fragment> tag.
If you use the static fragment, the fragments methods are invoked just when the fragment appears. Is it possible to achieve the same behaviour without using the fragment tag? I need a way to avoid the rendering of the fragment if it is not in the layout.
Thanks
I have found one fix to this. It is slightly different from the suggested Handling orientation changes with Fragments one:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (!fragment.isInLayout() && container == null) return null;
...
}
In this way you can avoid the case when the fragment is statically put into the layout (in that case the container is null but the method isInLayout() returns true.
By the way it is still weird to me this behaviour.
AFAIK, fragments work almost as Activities. They have the same lifecycle. http://developer.android.com/reference/android/app/Fragment.html#Lifecycle So, if you don't have references to them, it won't make them close. They are referenced by the system and live by themselves. So, you should finish them somehow.

Categories

Resources