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);
Related
Inside onCreateView i can instance View with the inflate, in this way:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if(savedInstanceState == null) {
v = inflater.inflate(R.layout.fragment_my_team, container, false);
setUpRecyclerView(v);
}
return v;
}
Now, if launch a second activity when return in the first activity, in this fragment, the View is null because onCreateView it's already called.
I don't know a to instance the view.
Is there a solution of that?
Get rid of the if(savedInstanceState == null) validation and create & return your view every time onCreateView is invoked.
I am using fragments to design my screen.When I navigate back to another fragment (from the back stack), the onCreateView(...) method gets called each time even if the fragment has already been created.How to avoid that the method onCreateView(...) gets called each time and make sure it's called only once (when it's created the first time)?
You can cache your inflated view to the local field if your want. For example:
public class ExampleFragment extends Fragment {
private View fragmentView;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
if (fragmentView == null) {
fragmentView = inflater.inflate(R.layout.you_super_view_id, container);
}
return fragmentView;
}
}
But practically, it's ok that pager is reinflating views because it keeps only part of all fragments in memory at the time. So, I think the best idea is to let it work as it should
Here's the problem
I have a Fragment class DisplayFragment and I already have one show in the content frame, then I do
DisplayFragment a = DisplayFragment.newInstance();
getSupportFragmentManager().beginTransaction()
.replace(R.id.contentFrame, DisplayFragment)
.commit();
Then I want to get the view of fragment a using View v = a.getView();, but it return a null view.
Can anyone tell me why? Cause I have to change some view setting of the new Fragment.
onCreateView() in DisplayFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_display, container, false);
//Some TextView setup
Button button = (Button) view.fineViewById(R.id.button);
return view; }
You need to use delay or put your View v = a.getView(); in loop which will watch first that your fragment is successfully attached, created and added in your activity or not. For this you can check with this isAdded() and isInLayout() if both return true then only call getView()
Now why this, as you add/replace fragment with commit with will fragment will class will be execute first it'll be start Fragment life cycle that is onAttach(), onCreate(), onCreateView() and so on. Now you will getting null from getView() just because your view is not created still. Fragment Life Cycle. If you doubt regarding this let me know.
I assume that you call View v = a.getView(); right after commit?
Because getView method only return not null value after onCreateView returned.
In your case, after called commit(), it take time to complete all the lifecyle callback of DisplayFragment a (from onCreate -> onCreatedView,..).
So that, right after commit(), the getView method still return null.
Declare DisplayFragment a; as Class Reference. Because after commit you want to just access View v = a.getView(); it unavailable due to fragment Life Cycle. You can get after execute block of code.
Make sure you have to mentioned OnCreateView() Method on class DisplayFragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
// We have different layouts, and in one of them this
// fragment's containing frame doesn't exist. The fragment
// may still be created from its saved state, but there is
// no reason to try to create its view hierarchy because it
// won't be displayed. Note this is not needed -- we could
// just run the code below, where we would create and return
// the view hierarchy; it would just never be used.
return null;
}
Log.i("Right", "onCreateView()");
return inflater.inflate(R.layout.right, container, false);
}
I had same problem as like you.
As the transaction of fragment did not takes place immediately. Thats why sometime the findViewById() does not work properly. But we can execute the pending transaction by using executePendingTransactions() method. I have used following code in my project to execute the pedingTransactions.
Fragment f = (Fragment)(FragmentClass.class).newInstance();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.your_fragment_container_name,f).commit();
fm.executePendingTransactions(); //Notice the FragmentManager Class object
The app I'm currently developing has an action bar with 5 tabs (fragments). One of these fragment shows an alert dialog, but the layout is blank. I want to put a background image, so I created a layout for that fragment and used inflater.inflate(...) method to set the layout.
Problem is that line of code sets that layout to ALL fragments. How can I limit it just to the fragment I need? Here's my code:
public class MyFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
//...
AlertDialog ad = new AlertDialog.Builder(getActivity()).setTitle("Title")
//...
ad.show();
inflater.inflate(R.layout.fragment_my, container); //this is the layout I want to inflate to my fragment
return super.onCreateView(inflater, container, savedInstanceState);
}
Also tried to replace the last two lines with:
return inflater.inflate(R.layout.fragment_trovami, container);
but i'm getting this error:
07-27 16:19:46.768: E/AndroidRuntime(1998): java.lang.IllegalStateException:
The specified child already has a parent. You must call removeView() on the child's parent first.
Answer :
return inflater.inflate(R.layout.fragment_trovami, container,false);
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.