How to check if view was already loaded? (InflateException: Duplicate id) - android

I'm building an android app in which I use one Activity from which I can load several fragments. So I start with the FragmentA, and from that I load Fragment B as follows:
FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
tx.replace(R.id.content_frame, detailsFragment).addToBackStack(null).commit();
This works fine. When I press the backbutton, it also goes back to FragmentA perfectly well. The problem is that when I click on the button to go to FragmentB again I get an InflateException (Duplicate id 0x7f08007a, tag null, or parent id 0x0 with another fragment for com.ourcomp.fragment.DetailsFragment) on this line:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_details, null);
}
I think I need to check whether it was inflated already, but I don't really know how. Does anybody know how I can check wether the view was already inflated so that I can prevent this error?

After checking documentation again, I found:
The ViewGroup to be the parent of the inflated layout. Passing the container is important in order for the system to apply layout parameters to the root view of the inflated layout, specified by the parent view in which it's going.
So try to replace
return inflater.inflate(R.layout.fragment_details, null);
with
return inflater.inflate(R.layout.fragment_details, container);

Related

Android - How to access state of checkboxes in fragments from activity

So I have a class which has a tabbed layout of 4 fragments each with a list of checkboxes. I need to save the state of those checkboxes in a sqlite database, but I am not able to access them at all with findViewById from the activity (throws a nullpointerexception). How would I go about doing this? Thanks!
When you first add or replace any fragment.. add a tag for it.. then later use this is acticity
fragment f1 = getfragmentmanager.findfragmentByTag("tag1");
then you can get and save
f1.getCheckbox1().ischecked()...
amd so on...
you can use getFragmentManager.getFragments...
You can't access view elements in your fragment from your activity, it simply wasn't created for this. And why would you need to?
You can simply save the values of your checkboxes inside your fragment code, where you have full access to the entire view. You can still access your sqlite database inside a fragment, it doesn't have to be an activity.
In a fragment you can override the onCreateView and inflate the view.
http://developer.android.com/training/basics/fragments/creating.html
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.article_view, container, false);
TextView textView = (TextView) v.findViewById(R.id.testelement);
return v;
}
And find the elements by doing this.

Android - How the state of views are preserved during Fragment Transforamtion

This confuses me a lot.
I had two fragments, and I use FragmentTransaction.replace() the swap the two fragments. State of some input controls like RadioGroup and checkbox is always preserved when I switch to the other fragments and switch back again.
.
I set break point on my OnCreateView() of Fragment, and every swap seems to trigger the method and new views are created each time. The savedInstanceBundle is always null as well. Since the new views are created, how do they get the state of the old views?
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_fieldsetup_marking, container, false);
// ...
return v;
}
This effect is fine for my app, but I just want to know how it is implemented.
where are the states stored?
Where is the android SDK code to restore this (I can not find any in the class FragmentTransection).

Confusion regarding inflater.inflate Android documentation

I'm studying fragments from this link : http://developer.android.com/guide/components/fragments.html
There's a piece of code given as:
public static class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
I was confused about the attachToRoot parameter so I looked up on Stack Overflow for some help and found good answers on similar problem. So what I understand is if you set it to true, the fragment gets attached to the activity's root layout, and derives its layoutparams from there. If it's false it would simply return the root of the inflated layout and acts like a standalone view for a fragment (deriving the layout params from the passed in container).
Now I read further down in the documentation regarding attachToRoot for the above example:
A boolean indicating whether the inflated layout should be attached to
the ViewGroup (the second parameter) during inflation. (In this case,
this is false because the system is already inserting the inflated
layout into the container—passing true would create a redundant view
group in the final layout.)
I don't get the last parenthesis statement where it says that it should be false because we're already inserting the layout into the container. What does it mean that we're already inserting into the container without attachToRoot as true? If the parameter is true, how would the final layout have redundant view groups. An example to elaborate this part would be a great help. Thanks.
I don't usually answer my own questions, but after doing a bit more research for this, I thought that maybe this will help someone else. Although Marcin's answer is correct, but I'm just answering a bit more in detail.
As per code :
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
The second parameter container is a framelayout with id fragment_container that activity uses to add fragment to it's layout.
Now, if we dive deeper into inflate method of LayoutInflater class, this is the code (I'm just highlighting the relevant parts of code rather than the whole part) :
// The view that would be returned from this method.
View result = root;
// Temp is the root view that was found in the xml.
final View temp = createViewFromTag(root, name, attrs, false);
Firstly, it creates a temp view from the supplied root.
In case attachToRoot is true, it does this :
if (root != null && attachToRoot) {
root.addView(temp, params);
}
It adds the temp view created above to the root view (i.e. container).
In case attachToRoot is false, it does this:
if (root == null || !attachToRoot) {
result = temp;
}
As quite evident, in case attachToRoot is true, it simply returns the root (fragment_container i.e the id activity uses to place the fragment inside it.) after adding the temp view to it (Root view in example_fragment in this case)).
In case attachToRoot is false, it simply returns the root of the fragment's xml, i.e. the container parameter is just used to get layoutParams for fragment's root view (since it doesn't have a root, so it needs params from somewhere).
The problem in case of true, arises in above example, because the return value is root (fragment_container with added view temp, and fragment_container by default has a parent already.). Now, if you try to do a fragment transaction, you're trying to add a child view fragment_container(which already has a parent to another xml (framelayout that you defined to add the fragment to).
Due to this, Android throws the following exception:
if (child.getParent() != null) {
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
}
Problem while setting it to true and returning is that the view returned already has a parent, so can't be used else where. Other way, you could make a separate view group inside onCreateView (maybe a LinearLayout), set the parameter to true, and return the view. Then it'll work fine because the viewgroup won't have an existing parent.
This is my understanding of the above problem, I might be wrong in which case I'd like any Android expert to correct this.
It means that in case on onCreateView() returned View will be attached to container view anyway, so setting it to true in your onCreateView() would cause it to be added twice to container layout, which isn't what you usually want. And setting root view to not null and still have attachToRoot false allows inflated view to derive from root, w/o being added.
check this
View v =getLayoutInflater.inflate(R.layout.example_fragment, viewgroup);
and also this
View v =getLayoutInflater.inflate(R.layout.example_fragment, null);
now if you call this for the first scenario
Log.v("testing",String.valueOf(v.getParent() == null));
you will get false as the output, but when you check that on the second line you will get true.
Simple understanding is if you specify a parent(ViewGroup) it is attached to it, but if you add the last parameter the you are telling the inflater to skip the attachment of the View so your returned View has no parent, but if you specify null, who's going to be attached to? NOBODY so the returned View has no parent, and also like you stated it derives layoutParameters for the View.
If you dont add the last parameter the View will have its parent as the Activity View and hence will be returned in your OncreateView having already a parent, before it will be added, which will cause some Exceptions as a View cannot have different daddies and the Fragment will not be able to manage the View itself.
if add true return null from your oncreateView
The View that you return from onCreateView() method of a fragment, will be attached to the container of the fragment by the system. So the third parameter of inflate() method should be false in this case. If you set it to true then it will be attached to the root twice. So you should set it to false in this case.
Now, the inflated view derives its layout parameters from the second parameter of inflate() method not from the third boolean parameter.
ok from android official documentation Android documentation
What is Fragment?
A Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. You can think of a fragment as a modular section of an activity, which has its own lifecycle, receives its own input events, and which you can add or remove while the activity is running (sort of like a "sub activity" that you can reuse in different activities).
How to Use Fragment in Activity?
A fragment must always be embedded in an activity and the fragment's lifecycle is directly affected by the host activity's lifecycle. For example, when the activity is paused, so are all fragments in it, and when the activity is destroyed, so are all fragments. However, while an activity is running (it is in the resumed lifecycle state), you can manipulate each fragment independently, such as add or remove them.
What is Fragment Transaction
you can manipulate each fragment independently, such as add or remove them. When you perform such a fragment transaction, you can also add it to a back stack that's managed by the activity—each back stack entry in the activity is a record of the fragment transaction that occurred. The back stack allows the user to reverse a fragment transaction (navigate backwards), by pressing the Back button.
How Fragment and Activity Interact with each other
When you add a fragment as a part of your activity layout, it lives in a ViewGroup inside the activity's view hierarchy and the fragment defines its own view layout. You can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a element, or from your application code by adding it to an existing ViewGroup.
Fragment Lifecycle methods onCreateView()
onCreate()
onPause()
And your question is
What does it mean that we're already inserting into the container without attachToRoot as true? If the parameter is true, how would the final layout have redundant view groups
and here is answar
suppose you have added already in your activity layout then you do not' need to make last parameter to true.because each time you perform add or remove of fragment their is a fragment transaction.
However if you have not added already a fragment in your layout then you can set it to true.
read this in doc
You can insert a fragment into your activity layout by declaring the fragment in the activity's layout file, as a element, or from your application code by adding it to an existing ViewGroup. However, a fragment is not required to be a part of the activity layout; you may also use a fragment without its own UI as an invisible worker for the activity.
all fragment transaction are added on activity back stack

Android Development, how does this line of code become produced?

i'm reading this android dev book and im stuck understanding how this line of code is error free (please keep in mind i've gotten rid of some code because for more focus on this part.
public View onCreateView(LayoutInflater layoutToInflate, ViewGroup parent, Bundle saveState)
{
View v = layoutToInflate.inflate(R.layout.activity_main_fragment,parent,false);
return v;
}
from what i believe, i need a method that returns a view because the Class extends from a Fragment class, not an activity so i have to explicitly find the view, the parameters are straight forward what i dont understand is how we create a view and set it equal to layoutToInflate...false;
I think you have a misunderstanding what the concepts of Fragments are. They reside inside an Activity. If a Fragment has a UI, it needs the parent Activity to also have a UI. That also means Fragments have a ViewParentbelonging to an Activity. This parent is given to the Fragment by the ViewGroup parent argument. So when creating a Fragment with a UI, you need to inflate the layout belonging to your Fragment and pass it to the Activity, which adds it to the ViewGroup parent. So that's why you get a LayoutInflater to inflate your Fragment's view:
View v = layoutToInflate.inflate(R.layout.activity_main_fragment,parent,false);
Afterwards you return it to give it to the parent Activity.
layoutToInflate is a variable of LayoutInflater and R.layout.activity_main_fragment is the name of the layout file to be inflated.

Access Activity within Fragment

Im making an App. And I want to access my 3 main activities into 3 different fragments. i use viewpager to swap activities but it only show layouts do not work on its functionality. Then i used Fragment to use functions. but my problem is same its only show layouts not is functions.
i made 3 different fragment for 3 activities and use
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.settings, container, false);
return v;
}
method.
idont know how to use onActivityCreated() method or getActivity(). please help me..
i search all of it about it but cannot done yet.. :(
To access Widget Of layout just use this
View.findViewById();

Categories

Resources