findFragmentById always returns null - android

I'm defining an ID for my fragment in the xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test_fragment"
...
Then I add this fragment in the activity's onCreate method:
MyFragment myFragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_container, myFragment);
fragmentTransaction.commit();
This is all working fine. Replacing fragments and is also working.
Later I'm trying to retrieve this fragment by its ID in one of the activity's methods:
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.test_fragment);
Doing so leads to myFragment being null. Always.
When I try to do the same with tags instead of IDs I can retrieve the fragment by its tag without any problems:
MyFragment myFragment = new MyFragment();
fragmentTransaction.add(R.id.fragment_container, myFragment, "testfragment");
fragmentTransaction.commit();
...
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentByTag("testfragment");
Why can't findFragmentById find the fragment, but findFragmentByTag does so? Am I missing something?

R.id.test_fragment is not the ID of your fragment but the id of your LinearLayout
Calling add(int containerViewId, Fragment fragment) will add a fragment without a tag.
So or you use add(int containerViewId, Fragment fragment, String tag) and you get back your fragment using your tag (as an ID)

Use the <FrameLayout> tag as a container in your layout file. Later to replace the fragments from your activity dynamically, you can use the ID of the <FrameLayout> container to replace the fragments in your activity.
<FrameLayout
android:id="#+id/test_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/test_fragment"
it should be a fragment not a LinearLayout
<fragment android:name="com.example.yourfragment"
android:id="#+id/test_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />

I was using android.support.v4.app.Fragment in my layout while calling getFragmentManager() which actually searched for android.app.Fragment subclasses and I got null.
So the fix was to call getSupportFragmentManager() instead.
In general make sure the package of a fragment you are subclassing and using in your layout is the same returned by the corresponding FragmentManager which performs search.

Or, you should have instead used :
(MyFragment) getFragmentManager().findFragmentById(R.id.fragment_container);

R.id.test_fragment is your LinearLayout ID not your Fragment.
You can define and id on a fragment when it is inflated from an xml like in this sample http://developer.android.com/guide/topics/fundamentals/fragments.html#Adding

The reasons mentioned above are valid but another possible reason is that you are trying to search for the fragment while being in a fragment this also results in fragmentManager.findFragmentById to return null. We should use childFragmentManager.findFragmentById to find the fragment inside a fragment.
According to the official documentation.
public final androidx.fragment.app.FragmentManager getChildFragmentManager()
Return a private FragmentManager for placing and managing Fragments
inside of this Fragment.

FragmentB fragmentB =
(FragmentB) getSupportFragmentManager().findFragmentById(R.id.containerb);
if(fragmentB != null)
{
fragmentB.showuserResponse(msg);
}
Use container id as fragment id. And then check for null reference.

fragmentTransaction.add(R.id.fragment_container, myFragment);
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.test_fragment);
Please notice the difference.
You should pass R.id.fragment_container as the argument to findFragmentById, as you pass it to the add function, instead of R.id.test_fragment
By the way , according to the inner implementation of the two functions, it should be right that the id can be
that of its container view.

Related

How do I programmatically add this fragment to my fragment?

I am trying to display a nested ListFragment inside my DialogFragment.
Apparently I cannot just declare a <fragment> in the XML for my DialogFragment layout because fragments-in-fragments need the childFragmentManager. So I am trying to do this in my DialogFragment:
Fragment listfragment = new ClassThatExtendsListFragment();
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
transaction.add(????????, listfragment).commit();
I have absolutely no idea what resource ID I need to put in the ???????? section, or how I'd even go about assigning it.
simply add FrameLayout in you layout. suppose you gave it's id as "container",
Fragment exampleFragment = new ExampleFragment();
getSupportFragmentManager().beginTransaction()
.add(R.id.container, exampleFragment).commit();
My requirement also was same like you. below code worked for me.
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MyTripFragment myTripFragment = new MyTripFragment();
fragmentTransaction.add(R.id.fragment_container, myTripFragment);
fragmentTransaction.commit();
XML code:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Hope it will help for you.
I'm not sure what type of layout you're using for your DialogFragment, but generally in the XML that DialogFragment inflates you need to add a FrameLayout and importantly give it an ID. Then when you do your fragment transaction you pass in the resource id of that FrameLayout
XML:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</LinearLayout>
If you want to use nested fragments you'll need to call getChildFragmentManager():
FragmentManager fragmentManager = getChildFragmentManager()
Then for your fragment transaction:
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, new MyFragment()).commit();
You might want to use the add method instead of replace, but thats up to you
You might also want to add the previous fragment to the backstack if you want the enable back button presses:
fragmentTransaction.replace(R.id.fragment_container, new MyFragment()).addToBackStack(null).commit();

How can I get Fragment from View?

I added some Fragment into a TableLayout and I want to manage them from my container Activity, so I used this:
Fragment fragment = (Fragment) tableLayout.getChildAt(i);
but getChildAt(int) returns a View and a View could NOT cast to Fragment
I don't understand why people are down-voting your question. Fragments can be very confusing at times, especially for beginners. To understand your problem, you must learn what is a Fragment and how they are used.
To start with, a View is something that has an existence on the screen. Examples include: TextView, EditText, Button, etc. They are placed inside "layouts" written in Xml or Java/Kotlin. These layouts are shown using an Activity.
Now, a Fragment is not a View. It does not have any existence on the screen at all. Instead, it's a class that simply manages a "layout" — kinda similar to an Activity. If you need the View returned by your Fragment's onCreateView(), you can directly use findViewById() within your Activity.
If you need a reference to your Fragment, there are two possible ways of doing this:
1) If you added the Fragment programmatically like this
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container_viewgroup, myFragment, FRAGMENT_TAG)
.commit();
You can use:
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
2) If you added the Fragment inside an XML layout like this:
<fragment android:name="com.example.android.fragments.HeadlinesFragment"
android:id="#+id/fragmentContainer"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
You can use this:
getFragmentManager().findFragmentById(R.id.fragmentContainer);
Basically, each Activity has a FragmentManager class that maintains all the active Fragments, and there are two ways of finding them: Using a unique TAG that you pass while showing a fragment, or passing the container view-ID where the fragment was added.
For people looking how to actually get a reference to the Fragment object from a View there is now a method in FragmentManager called findFragment(View) (reference)
//in Java
FragmentManager.findFragment(view)
//in Kotlin there is an extension function
view.findFragment()
Be careful - it will throw an IllegalStateException if the view was not added via a fragments onCreateView.
You can not get a fragment like this. You will have to add fragment with a tag and retrieve it by that tag.
to add a fragment do following:
getFragmentManager().beginTransaction().add(R.id.container, fragment, "tagTofindFragment");
to get fragment:
fragment = getFragmentManager().findFragmentByTag("tagTofindFragment");
Here tagTofindFragment is that tag that should be unique among your fragments.

Replaced fragment still received events

I am writing an android app using ActionBarSherlock
My layout file is:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<FrameLayout
android:id="#+id/fragment_menu"
android:layout_width="#dimen/menu_size"
android:layout_height="wrap_content"/>
<FrameLayout
android:id="#+id/dummy"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Depending the category is selected in Menu fragment, I replace the fragment in dummy FrameLayout.Eg:
Bundle extras = new Bundle();
extras.putInt(ProgramDetailFrament.EXTRA_PROGRAM_ID, programId);
final ProgramDetailFrament fragment = ProgramDetailFrament.newInstance(extras);
getSupportFragmentManager().beginTransaction()
.replace(R.id.dummy, fragment)
.addToBackStack(null)
.commit();
getSupportFragmentManager().executePendingTransactions();
But the replaced fragment still receives touch/click event when I interact with the visible fragment. I don't know whether SherlockFragment is related to this issue?
I solved that by setting click event on the root layout of the visible fragment and do nothing in this event. But It seems a ugly solution.
Anyone knows how to solve it.
Thanks in advance.
As you state in your question, you're trying to replace a Fragment with another, so you should use the replace method of FragmentTransaction.
Here's roughly how to do it :
Bundle extras = new Bundle();
extras.putInt(ProgramDetailFrament.EXTRA_PROGRAM_ID, programId);
ProgramDetailFrament fragment = ProgramDetailFrament.newInstance(extras);
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.id_of_fragment_container, fragment, DETAIL_FRAGMENT_TAG);
ft.commit();
I hope this helps ;-)
You actually need to use the replace function instead of add. What you're doing is adding a fragment on top of the other one, so you're creating a stack of fragments which are all still visible, only you don't see them because the top fragment covers all the other ones.
Use replace instead of add:
getSupportFragmentManager().beginTransaction()
.replace(R.id.dummy, fragment)
.addToBackStack(null)
.commit();
getSupportFragmentManager().executePendingTransactions();
This will remove all the other fragments in the dummy container and add the fragment you selected.

Fragment was unable to replace with fragment in viewpager

I'm working with fragments with ViewPager concept. I'm creating a diary app in which I'm using only one fragment which gets all updates from database and show in it. Until this everything is fine...According to my requirement when i click on a button in fragment i need to show another fragment which allows the user to store the images.
My problem is.....
--If i use replace method in fragments it was not replacing properly in the sense if A is fragment which consists of viewpager and B is a fragment i want to replace.
--Then if i use replace B is visible but A also appears under the fragment B
FragmentManager m=getActivity().getSupportFragmentManager();
FragmentTransaction ft = getActivity().getSupportFragmentManager()
.beginTransaction();
Demobutton demobutton = new Demobutton();
ft.replace(R.id.lay, demobutton);
ft.commit();
Hope you guys understand my problem. If you feel my question is incomplete please let me know that.
I have two suggestions depending on how you use the DemoButton Fragment:
1) Maybe your issue is with nested fragments. You get the FragmentManager from the activity but if the Demobutton is already part of an fragment use getChildFragmentManager() of the outer fragment instead.
2) From my experience when using a ViewPager with Fragments the PagerAdapter of the ViewPager should do all the fragment transactions. You could extend and overwrite the class FragmentPagerAdapter from the support library in order to get the correct fragment in your ViewPager when you need it.
I've developed a small example app that achieves this without overwriting native classes.
The point is to use a fragment as a container.
In your ViewPagerAdapter:
#Override
public Fragment getItem(int position) {
/*
* IMPORTANT: This is the point. We create a RootFragment acting as
* a container for other fragments
*/
if (position == 0)
return new RootFragment();
else
return new StaticFragment();
}
RootFragment layout should look like:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/root_frame" >
</FrameLayout>
You could review my complete explanation here: https://stackoverflow.com/a/21453571/1631136

how to get a fragment added in an XML layout

I have a layout which includes a fragment as follows:
<fragment
android:id="#+id/mainImagesList"
android:name="com.guc.project.ImagesList"
android:layout_width="match_parent"
android:layout_height="62dp"
android:layout_below="#+id/addimagebutton"
android:layout_weight="1"
android:paddingTop="55dp" />
now, I need to get this fragment and cast it so I can manipulate it and the updates appear. How can i do so ?!
EDIT: I think I've managed to get the fragment, but when I change some variables, the changes don't appear !
You can get the fragment instance as follows:
getSupportFragmentManager().findFragmentById(R.id.yourFragmentId)
If the fragment is embedded in another fragment, you need getChildFragmentManager() but not getFragmentManager().
For example, in layout xml define the fragment like this:
<fragment
android:name="com.aventlabs.ChatFragment"
android:id="#+id/chatfragment"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_marginTop="50dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp" />
in Code, you can get the fragment instance like this:
FragmentManager f = getChildFragmentManager();
FragmentTransaction transaction = f.beginTransaction();
chatFragment = f.findFragmentById(R.id.chatfragment);
if (chatFragment != null) {
transaction.hide(chatFragment);
}
transaction.commit();
I did exactly the same in android and the simplest way to do this in using interfaces. I had an activity with 6 fragments and i needed to update only 3 of them.
I use this
final Integer numeroFragments = ((PagerAdapterOfe) mViewPager.getAdapter()).getCount();
for (int i=0; i<numeroFragments; i++) {
Object fragment = ((PagerAdapterOfe) mViewPager.getAdapter()).getItem(i);
// If the fragment implement my interface, update the list
if (fragment instanceof IOfertaFragment){
((IOfertaFragment) fragment).actualizaListaOfertas();
}
}
Where, PageAdapterOfe is my activity fragments adapter. I loop all of my fragments and search for those that implement my interface, when i found one, I execute the method defined by my interface and that is!
I use this code inside the activity that holds all the fragments, in response a broadcast signal, you can put it where you need.
The interface:
public interface IOfertaFragment {
public void actualizaListaOfertas();
}
You can find the fragment using findFragmentById (if you know the component it is included in) or by findFragmentByTag (if you know its tag)
I don't know which variables you want to update, but you can replace the fragment with another fragment using the FragmentTransaction API.
See http://developer.android.com/guide/components/fragments.html for examples.
If Fragment is included inside the layout file of Activity then it can be referenced by SupportFragmentManager like...
MyFragment myFragment= (MyFragment)getSupportFragmentManager().findFragmentById(R.id.FRAGMENTID)
If Fragment is included inside the layout file of another Fragment then it can be referenced by ChildFragmentManager like...
MyFragment myFragment= (MyFragment)getChildFragmentManager().findFragmentById(R.id.FRAGMENTID)

Categories

Resources