How does the container get passed to a fragment? - android

I'm attempting to understand someone else's code. They are using fragments (which I'm rather hazy on).
I know that a fragment starts up with onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState .. but I can't fathom where the "container" was set up.
where should I look?

container is handled by the Android framework, it typically refers to View passed by id in methods like FragmentTransaction's add(int containerViewId, Fragment fragment) or replace(int containerViewId, Fragment fragment).
For example, this is from the Developer's Guide:
ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.news_list, container, false);
return v;
}
The layout news_list is for this fragment.

Related

Fragment callback on attach complete in Activity

Is it possible to get the attach complete of a fragment in the hosting activity? I am new to Android.
Here is my code to add a fragment:
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
DecorationFragment fragment = new DecorationFragment();
ft.add(R.id.fragmentContainer,fragment,"decoration_fragment");
ft.commit();
I have 2 objects in the Fragment. I want to handle their click event in the Activity.
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_decoration, container, false);
mChangeTextColorButton = (Button) rootView.findViewById(R.id.changeTextColorButton);
mColorPallette = (LinearLayout)rootView.findViewById(R.id.color_pallette_linearView);
return rootView;
}
How to achieve this?
Not sure exactly what you're asking, but perhaps this is what you're looking for:
https://developer.android.com/reference/android/support/v4/app/FragmentActivity.html#onAttachFragment(android.support.v4.app.Fragment)
void onAttachFragment (Fragment fragment)
Called when a fragment is attached to the activity.
This is called after the attached fragment's onAttach and before the attached fragment's onCreate if the fragment has not yet had a previous call to onCreate.

FragmentManager with FragmentTabHost

I have an Activity that has a ViewPager with four Fragments. One of those Fragments must have two tabs inside of it so I tried FragmentTabHost.
private FragmentTabHost fragmentTabHost;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_zbritjet, container, false);
fragmentTabHost = (FragmentTabHost) view.findViewById(android.R.id.tabhost);
fragmentTabHost.setup(view.getContext(), getFragmentManager(), android.R.id.tabcontent);
fragmentTabHost.addTab(fragmentTabHost.newTabSpec("tab_ofertat").setIndicator("Ofertat"), OfertatItems.class, null);
fragmentTabHost.addTab(fragmentTabHost.newTabSpec("tab_bizneset").setIndicator("Bizneset"), BiznesetItems.class, null);
return view;
}
The problem is that android is throwing
java.lang.IllegalStateException: FragmentManager is already executing transactions
Stack trace:
android.support.v4.app.FragmentManagerImpl.ensureExecReady(FragmentManager.java:1946)
android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1992)
android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:762)
android.support.v4.app.FragmentTabHost.onAttachedToWindow(FragmentTabHost.java:289)
Try getChildFragmentManager() instead of getFragmentManager().
From the docs:
Return a private FragmentManager for placing and managing Fragments inside of this Fragment.

Fragment - Getting view already has a parent error on calling onCreateView

I am inflating a fragment from activity at runtime. So, in order to inflate the view of the fragment in the fragment class I called:
#Nullable
#Override
public View onCreateView(final LayoutInflater inflater, #Nullable final ViewGroup container, #Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.confirm_fragment, container);
}
At this moment I get a crash with logs:
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
But if I modify my method as:
#Nullable
#Override
public View onCreateView(final LayoutInflater inflater, #Nullable final ViewGroup container, #Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
return inflater.inflate(R.layout.confirm_fragment, null);
}
where I now specify my container as null, it works. But what I didn't understand is where did I specify a parent for the view in the code which was crashing?
Read from this link that why and when you pass parent container's instance or null in attachToRoot param.
From link:
Button button = (Button) inflater.inflate(R.layout.custom_button, mLinearLayout, false);
mLinearLayout.addView(button);
By passing in false, we say that we do not want to attach our View to the root
ViewGroup just yet. We are saying that it will happen at some other
point in time. In this example, the other point in time is simply the
addView() method used immediately below inflation.
So if you inflate with:
return inflater.inflate(R.layout.confirm_fragment, container);
First it will immediately attach confirm_fragment to container. After returning the view, fragment will be tried to be added to parent again implicitly, but since it has been added already, exception will be thrown:
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Hope you got the point.
where did I specify a parent for the view [...] ?
You add a Fragment dynamically by writing something like this:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(android.R.id.content, myFragment, FRAGMENT_TAG)
.addToBackStack(null)
.commit();
In add(), you specify where the Fragment should be displayed (in this case fullscreen) by passing the id of the desired container.
See also the method description in the reference developers.android.com:
containerViewId int: Optional identifier of the container this fragment is to be placed in. If 0, it will not be placed in a container.
I you don't add a Fragment to the UI (e.g. you need it for caching purposes as a retained fragment), onCreateView() will never be called.
So once onCreateView() is called, the parent for this Fragment already exists - the FragmentManager set it for you.
Try to use the following code:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.confirm_fragment, container, false);
return view;
}
You need to set attachToParent to false
Example:
inflater.inflate(R.layout.confirm_fragment, container,false);

How to set the right fragment to replace.

I’m doing a navigation drawer in my android app. On my onNavigationDrawerItemSelected function i try on item select to change the current fragment into a new one. The problem is that when I change the current fragment its take the initial status of it. maybe because i'm doing this way
fragmentManager.beginTransaction()
.replace(R.id.cont, new SessionsFragement())
.commit();
I declare a new instance of my fragment and i think it’s normal, its display me the initial status of the thing. On my fragment i've try to set a textView to see if i will say it when i call the fragement from tha navigation drawer but it's not the case.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_spot, container, false);
tata = (TextView) v.findViewById(R.id.tata);
tata.setText("karim");
return inflater.inflate(R.layout.fragment_spot, container, false);
}
So please can anyone help me to fix this.
In the snippet you posted you are inflating again the view. You should return the one you modified
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_spot, container, false);
tata = (TextView) v.findViewById(R.id.tata);
tata.setText("karim");
return v;
}

Set new layout in fragment

I'm trying to change the layout of a fragment during runtime under a particular condition.
The initial layout in inflated within the onCreateView():
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.cancel_video, null);
}
Then sometime later within the fragment code I would like to replace the initial layout with some other layout.
I've tried a few things so far; this is the latest that I have:
private void Something(){
if(checkLicenseStatus(licenseStatus, statusMessage)){
View vv = View.inflate(getActivity(), R.layout.play_video, null);
//more code
}
}
How can I accomplish this?
You cannot replace the fragment's layout once it is inflated. If you need conditional layouts, then you either have to redesign your layout and break it down into even smaller elemens like Fragments. Alternatively you can group all the layout elements into sub containers (like LinearLayout), then wrap them all in RelativeLayout, position them so they overlay each other and then toggle the visibility of these LinearLayouts with setVisibility() when and as needed.
Yes, I have done this in following way. When I need to set a new layout(xml), the following code snippet should be executed.
private View mainView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup containerObject, Bundle savedInstanceState){
super.onCreateView(inflater, containerObject, savedInstanceState);
mainView = inflater.inflate(R.layout.mylayout, null);
return mainView;
}
private void setViewLayout(int id){
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mainView = inflater.inflate(id, null);
ViewGroup rootView = (ViewGroup) getView();
rootView.removeAllViews();
rootView.addView(mainView);
}
Whenever I need to change the layout I just call the following method
setViewLayout(R.id.new_layout);
Use a FragmentTransaction through the FragmentManger
FragmentManager fm = getFragmentManager();
if (fm != null) {
// Perform the FragmentTransaction to load in the list tab content.
// Using FragmentTransaction#replace will destroy any Fragments
// currently inside R.id.fragment_content and add the new Fragment
// in its place.
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_content, new YourFragment());
ft.commit();
}
The code for the class YourFragment is just a LayoutInflater so that it returns a view
public class YourFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.your_fragment, container, false);
return view;
}
}
I will change whole layout. You can change only a specific portion of your layout.
Add a root FrameLayout in your_layout.xml, it contains nothing.
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fl_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Set your content in the java code.
ViewGroup flContent = findViewById(R.id.fl_content);
private void setLayout(int layoutId) {
flContent.removeAllViews();
View view = getLayoutInflater().inflate(layoutId, flContent, false);
flContent.addView(view);
}
You can change layoutId free at some point.
If you have some listeners, you must set again.

Categories

Resources