Get the current fragment object - android

In my main.xml I have
<FrameLayout
android:id="#+id/frameTitle"
android:padding="5dp"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:background="#drawable/title_bg">
<fragment
android:name="com.fragment.TitleFragment"
android:id="#+id/fragmentTag"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</FrameLayout>
And I'm setting fragment object like this
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment newFragment = new FragmentType1();
fragmentTransaction.replace(R.id.frameTitle, casinodetailFragment, "fragmentTag");
// fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
It is setting different types of Fragment objects (FragmentType2,FragmentType3,...) at different time. Now at some point of time I need to identify which object is currently there.
In short I need to do something like this:
Fragment currentFragment = //what is the way to get current fragment object in FrameLayout R.id.frameTitle
I tried the following
TitleFragment titleFragmentById = (TitleFragment) fragmentManager.findFragmentById(R.id.frameTitle);
and
TitleFragment titleFragmentByTag = (TitleFragment) fragmentManager.findFragmentByTag("fragmentTag");
But both the objects (titleFragmentById and titleFragmentByTag ) are null
Did I miss something?
I'm using Compatibility Package, r3 and developing for API level 7.
findFragmentById() and findFragmentByTag() will work if we have set fragment using fragmentTransaction.replace or fragmentTransaction.add, but will return null if we have set the object at xml (like what I have done in my main.xml). I think I'm missing something in my XML files.

Now at some point of time I need to identify which object is currently there
Call findFragmentById() on FragmentManager and determine which fragment is in your R.id.frameTitle container.
If you are using the androidx edition of Fragment — as you should in modern apps — , use getSupportFragmentManager() on your FragmentActivity/AppCompatActivity instead of getFragmentManager()

Try this,
Fragment currentFragment = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
this will give u the current fragment, then you may compare it to the fragment class and do your stuffs.
if (currentFragment instanceof NameOfYourFragmentClass) {
Log.v(TAG, "find the current fragment");
}

I think you can use onAttachFragment event may be useful to catch which fragment is active.
#Override
public void onAttachFragment(Fragment fragment) {
// TODO Auto-generated method stub
super.onAttachFragment(fragment);
Toast.makeText(getApplicationContext(), String.valueOf(fragment.getId()), Toast.LENGTH_SHORT).show();
}

I think you should do:
Fragment currentFragment = fragmentManager.findFragmentByTag("fragmentTag");
The reason is because you set the tag "fragmentTag" to the last fragment you have added (when you called replace).

You can get the list of the fragments and look to the last one.
FragmentManager fm = getSupportFragmentManager();
List<Fragment> fragments = fm.getFragments();
Fragment lastFragment = fragments.get(fragments.size() - 1);
But sometimes (when you navigate back) list size remains same but some of the last elements are null. So in the list I iterated to the last not null fragment and used it.
FragmentManager fm = getSupportFragmentManager();
if (fm != null) {
List<Fragment> fragments = fm.getFragments();
if (fragments != null) {
for(int i = fragments.size() - 1; i >= 0; i--){
Fragment fragment = fragments.get(i);
if(fragment != null) {
// found the current fragment
// if you want to check for specific fragment class
if(fragment instanceof YourFragmentClass) {
// do something
}
break;
}
}
}
}

This is the simplest solution and work for me.
1.) you add your fragment
ft.replace(R.id.container_layout, fragment_name, "fragment_tag").commit();
2.)
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentById(R.id.container_layout);
if(currentFragment.getTag().equals("fragment_tag"))
{
//Do something
}
else
{
//Do something
}

It might be late but I hope it helps someone else, also #CommonsWare has posted the correct answer.
FragmentManager fm = getSupportFragmentManager();
Fragment fragment_byID = fm.findFragmentById(R.id.fragment_id);
//OR
Fragment fragment_byTag = fm.findFragmentByTag("fragment_tag");

Maybe the simplest way is:
public MyFragment getVisibleFragment(){
FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
List<Fragment> fragments = fragmentManager.getFragments();
for(Fragment fragment : fragments){
if(fragment != null && fragment.getUserVisibleHint())
return (MyFragment)fragment;
}
return null;
}
It worked for me

You can create field in your parent Activity Class:
public class MainActivity extends AppCompatActivity {
public Fragment fr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
And then inside each fragment class:
public class SomeFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
((MainActivity) getActivity()).fr = this;
}
Your 'fr' field is current fragment Object
It's working also with popBackStack()

I know it's been a while, but I'll this here in case it helps someone out.
The right answer by far is (and the selected one) the one from CommonsWare. I was having the same problem as posted, the following
MyFragmentClass fragmentList =
(MyFragmentClass) getSupportFragmentManager().findFragmentById(R.id.fragementID);
kept on returning null. My mistake was really silly, in my xml file:
<fragment
android:tag="#+id/fragementID"
android:name="com.sf.lidgit_android.content.MyFragmentClass"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
The mistake was that I had android:tag INSTEAD OF android:id.

Do a check (which fragment in the activity container) in the onStart method;
#Override
protected void onStart() {
super.onStart();
Fragment fragmentCurrent = getSupportFragmentManager.findFragmentById(R.id.constraintLayout___activity_main___container);
}
Some check:
if (fragmentCurrent instanceof MenuFragment)

#Hammer response worked for me, im using to control a floating action button
final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(final View view) {
android.app.Fragment currentFragment = getFragmentManager().findFragmentById(R.id.content_frame);
Log.d("VIE",String.valueOf(currentFragment));
if (currentFragment instanceof PerfilFragment) {
PerfilEdit(view, fab);
}
}
});

If you are extending from AbstractActivity, you could use the getFragments() method:
for (Fragment f : getFragments()) {
if (f instanceof YourClass) {
// do stuff here
}
}

If you are defining the fragment in the activity's XML layour then in the Activity make sure you call setContentView() before calling findFragmentById().

If you are using the BackStack...and ONLY if you are using the back stack, then try this:
rivate Fragment returnToPreviousFragment() {
FragmentManager fm = getSupportFragmentManager();
Fragment topFrag = null;
int idx = fm.getBackStackEntryCount();
if (idx > 1) {
BackStackEntry entry = fm.getBackStackEntryAt(idx - 2);
topFrag = fm.findFragmentByTag(entry.getName());
}
fm.popBackStack();
return topFrag;
}

This will give you the current fragment class name -->
String fr_name = getSupportFragmentManager().findFragmentById(R.id.fragment_container).getClass().getSimpleName();

you can check which fragment is currently loaded by this
supportFragmentManager.addOnBackStackChangedListener {
val myFragment = supportFragmentManager.fragments.last()
if (null != myFragment && myFragment is HomeFragment) {
//HomeFragment is visible or currently loaded
} else {
//your code
}
}

I use the following function in Kotlin:
supportFragmentManager.fragments.run {
getOrNull(size - 1)?.let { currentFragment ->
...
}
}

I recently worked on an activity involving multiple fragments so thought to share the method I used here:
Firstly, I declared a function getCurrentFragment() which returned me, yeah you guessed it, the current fragment, lol.
private fun getCurrentFragment(): Fragment? {
return supportFragmentManager.findFragmentById(R.id.fragmentContainerView)
}
Then I override the onBackPressed function in the activity to define the navigation within fragments. Suppose, I wanted to show fragment 2 if user is in fragment 3 and presses back so I did something like this to achieve this
override fun onBackPressed() {
if (getCurrentFragment() is Fragment3) {
showFragment2()
} else {
super.onBackPressed()
}
}
And in showFragment2() I did something like this:
private fun showFragment2() {
val fragment = Fragment2.newInstance()
supportFragmentManager.commit {
replace(R.id.FragmentContainerView, fragment, "Add a tag here")
}
}
I think this should give better idea to people looking on how to navigate through fragments within an activity.

Related

How can I switch between two fragments, without recreating the fragments each time?

I'm working on an android application, that uses a navigation drawer to switch between two fragments. However, each time I switch, the fragment is completely recreated.
Here is the code from my main activity.
/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
android.support.v4.app.Fragment fragment;
String tag;
android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager();
switch(position) {
case 0:
if(fragmentManager.findFragmentByTag("one") != null) {
fragment = fragmentManager.findFragmentByTag("one");
} else {
fragment = new OneFragment();
}
tag = "one";
break;
case 1:
if(fragmentManager.findFragmentByTag("two") != null) {
fragment = fragmentManager.findFragmentByTag("two");
} else {
fragment = new TwoFragment();
}
tag = "two";
break;
}
fragment.setRetainInstance(true);
fragmentManager.beginTransaction().replace(R.id.container, fragment, tag).commit();
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mNavTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
I've set up some debug logging, and every time selectItem is called, one fragment is destroyed, while the other is created.
Is there any way to prevent the fragments from being recreated, and just reuse them instead?
After #meredrica pointed out that replace() destroys the fragments, I went back through the FragmentManager documentation. This is the solution I've come up with, that seems to be working.
/* The click listener for ListView in the navigation drawer */
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int position) {
android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager();
switch(position) {
case 0:
if(fragmentManager.findFragmentByTag("one") != null) {
//if the fragment exists, show it.
fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("one")).commit();
} else {
//if the fragment does not exist, add it to fragment manager.
fragmentManager.beginTransaction().add(R.id.container, new OneFragment(), "one").commit();
}
if(fragmentManager.findFragmentByTag("two") != null){
//if the other fragment is visible, hide it.
fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("two")).commit();
}
break;
case 1:
if(fragmentManager.findFragmentByTag("two") != null) {
//if the fragment exists, show it.
fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("two")).commit();
} else {
//if the fragment does not exist, add it to fragment manager.
fragmentManager.beginTransaction().add(R.id.container, new TwoFragment(), "two").commit();
}
if(fragmentManager.findFragmentByTag("one") != null){
//if the other fragment is visible, hide it.
fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("one")).commit();
}
break;
}
// update selected item and title, then close the drawer
mDrawerList.setItemChecked(position, true);
setTitle(mNavTitles[position]);
mDrawerLayout.closeDrawer(mDrawerList);
}
I also added this bit, but I'm not sure if it's necessary or not.
#Override
public void onDestroy() {
super.onDestroy();
FragmentManager fragmentManager = getSupportFragmentManager();
if(fragmentManager.findFragmentByTag("one") != null){
fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("one")).commit();
}
if(fragmentManager.findFragmentByTag("two") != null){
fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("two")).commit();
}
}
Use the attach/detach method with tags:
Detach will destroy the view hirachy but keeps the state, like if on the backstack; this will let the "not-visible" fragment have a smaller memory footprint. But mind you that you need to correctly implement the fragment lifecycle (which you should do in the first place)
Detach the given fragment from the UI. This is the same state as when it is put on the back stack: the fragment is removed from the UI, however its state is still being actively managed by the fragment manager. When going into this state its view hierarchy is destroyed.
The first time you add the fragment
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.add(android.R.id.content, new MyFragment(),MyFragment.class.getSimpleName());
t.commit();
then you detach it
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.detach(MyFragment.class.getSimpleName());
t.commit();
and attach it again if switched back, state will be kept
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()));
t.commit();
But you always have to check if the fragment was added yet, if not then add it, else just attach it:
if (getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()) == null) {
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.add(android.R.id.content, new MyFragment(), MyFragment.class.getSimpleName());
t.commit();
} else {
FragmentTransaction t = getSupportFragmentManager().beginTransaction();
t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()));
t.commit();
}
The replace method destroys your fragments. One workaround is to set them to Visibility.GONE, another (less easy) method is to hold them in a variable. If you do that, make sure you don't leak memory left and right.
I did this before like this:
if (mPrevFrag != fragment) {
// Change
FragmentTransaction ft = fragmentManager.beginTransaction();
if (mPrevFrag != null){
ft.hide(mPrevFrag);
}
ft.show(fragment);
ft.commit();
mPrevFrag = fragment;
}
(you will need to track your pervious fragment in this solution)
I guess you can not directly manipulate the lifecycle mechanisms of your Fragments. The very fact that you can findFragmentByTag is not very bad. It means that the Fragment object is not recreated fully, if it is already commited. The existing Fragment just passes all the lifecycle steps each Fragment has - that means that only UI is "recreated".
It is a very convenient and useful memory management strategy - and appropriate, in most cases. Fragment which is gone, has the resources which have to be utilized in order to de-allocate memory.
If you just cease using this strategy, the memory usage of your application could increase badly.
Nonetheless, there are retained fragments, which lifecycle is a bit different and do not correspond to the Activity they are attached to. Typically, they are used to retain some things you want to save, for example, to manage configuration changes
However, the fragment [re]creation strategy depends on the context - that is, what you would like to solve, and what are the trade-offs that you are willing to accept.
Just find the current fragment calling getFragmentById("id of your container") and then hide it and show needed fragment.
private void openFragment(Fragment fragment, String tag) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment existingFragment = fragmentManager.findFragmentByTag(tag);
if (existingFragment != null) {
Fragment currentFragment = fragmentManager.findFragmentById(R.id.container);
fragmentTransaction.hide(currentFragment);
fragmentTransaction.show(existingFragment);
}
else {
fragmentTransaction.add(R.id.container, fragment, tag);
}
fragmentTransaction.commit();
}
Same idea as Tester101 but this is what I ended up using.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
Fragment oldFragment = fragmentManager.findFragmentByTag( "" + m_lastDrawerSelectPosition );
if ( oldFragment != null )
fragmentTransaction.hide( oldFragment );
Fragment newFragment = fragmentManager.findFragmentByTag( "" + position );
if ( newFragment == null )
{
newFragment = getFragment( position );
fragmentTransaction.add( R.id.home_content_frame, newFragment, "" + position );
}
fragmentTransaction.show( newFragment );
fragmentTransaction.commit();
Hide easily in kotlin using extensions:
fun FragmentManager.present(newFragment: Fragment, lastFragment: Fragment? = null, containerId: Int) {
if (lastFragment == newFragment) return
val transaction = beginTransaction()
if (lastFragment != null && findFragmentByTag(lastFragment.getTagg()) != null) {
transaction.hide(lastFragment)
}
val existingFragment = findFragmentByTag(newFragment.getTagg())
if (existingFragment != null) {
transaction.show(existingFragment).commit()
} else {
transaction.add(containerId, newFragment, newFragment.getTagg()).commit()
}
}
fun Fragment.getTagg(): String = this::class.java.simpleName
Usage
supportFragmentManager.present(fragment, lastFragment, R.id.fragmentPlaceHolder)
lastFragment = fragment
Here's what I'm using for a simple 2 fragment case in Kotlin:
private val advancedHome = HomeAdvancedFragment()
private val basicHome = HomeBasicFragment()
override fun onCreate(savedInstanceState: Bundle?) {
...
// Attach both fragments and hide one so we can swap out easily later
supportFragmentManager.commit {
setReorderingAllowed(true)
add(R.id.fragment_container_view, basicHome)
add(R.id.fragment_container_view, advancedHome)
hide(basicHome)
}
binding.displayModeToggle.onStateChanged {
when (it) {
0 -> swapFragments(advancedHome, basicHome)
1 -> swapFragments(basicHome, advancedHome)
}
}
...
}
With this FragmentActivity extension:
fun FragmentActivity.swapFragments(show: Fragment, hide: Fragment) {
supportFragmentManager.commit {
show(show)
hide(hide)
}
}
How about playing with the Visible attribute?
this is a little late response.
if you're using view pager for fragments, set the off screen page limit of the fragment to the number of fragments created.
mViewPager.setOffscreenPageLimit(3); // number of fragments here is 3

Refresh Fragment at reload

In an android application I'm loading data from a Db into a TableView inside a Fragment. But when I reload the Fragment it displays the previous data. Can I repopulate the Fragment with current data instead of previous data?
I think you want to refresh the fragment contents upon db update
If so, detach the fragment and reattach it
// Reload current fragment
Fragment frg = null;
frg = getSupportFragmentManager().findFragmentByTag("Your_Fragment_TAG");
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.detach(frg);
ft.attach(frg);
ft.commit();
Your_Fragment_TAG is the name you gave your fragment when you created it
This code is for support library.
If you're not supporting older devices, just use getFragmentManager instead of getSupportFragmentManager
[EDIT]
This method requires the Fragment to have a tag.
In case you don't have it, then #Hammer's method is what you need.
This will refresh current fragment :
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (Build.VERSION.SDK_INT >= 26) {
ft.setReorderingAllowed(false);
}
ft.detach(this).attach(this).commit();
In case you do not have the fragment tag, the following code works well for me.
Fragment currentFragment = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
if (currentFragment instanceof "NAME OF YOUR FRAGMENT CLASS") {
FragmentTransaction fragTransaction = (getActivity()).getFragmentManager().beginTransaction();
fragTransaction.detach(currentFragment);
fragTransaction.attach(currentFragment);
fragTransaction.commit();
}
To refresh the fragment accepted answer will not work on Nougat and above version. To make it work on all os you can do following.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
fragmentManager.beginTransaction().detach(this).commitNow();
fragmentManager.beginTransaction().attach(this).commitNow();
} else {
fragmentManager.beginTransaction().detach(this).attach(this).commit();
}
you can refresh your fragment when it is visible to user,
just add this code into your Fragment this will refresh your fragment when it is visible.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
// Refresh your fragment here
getFragmentManager().beginTransaction().detach(this).attach(this).commit();
Log.i("IsRefresh", "Yes");
}
}
You cannot reload the fragment while it is attached to an Activity, where you get "Fragment Already Added" exception.
So the fragment has to be first detached from its activity and then attached. All can be done using the fluent api in one line:
getFragmentManager().beginTransaction().detach(this).attach(this).commit();
Update:
This is to incorporate the changes made to API 26 and above:
FragmentTransaction transaction = mActivity.getFragmentManager()
.beginTransaction();
if (Build.VERSION.SDK_INT >= 26) {
transaction.setReorderingAllowed(false);
}
transaction.detach(this).attach
(this).commit();
For more description of the update please see https://stackoverflow.com/a/51327440/4514796
If you are using NavController, try this (kotlin):
val navController = findNavController()
navController.run {
popBackStack()
navigate(R.id.yourFragment)
}
In case you are using Navigation Components
You can use navigate(this_fragment_id) to navigate to this fragment but in a new instance. Also you have to pop the backstack before to remove the actual fragment.
Kotlin
val navController: NavController =
requireActivity().findNavController(R.id.navHostFragment)
navController.run {
popBackStack()
navigate(R.id.this_fragment_id)
}
Java
NavController navController =
requireActivity().findNavController(R.id.navHostFragment);
navController.popBackStack();
navController.navigate(R.id.this_fragment_id);
MyFragment fragment = (MyFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
getSupportFragmentManager().beginTransaction().detach(fragment).attach(fragment).commit();
this will only work if u use FragmentManager to initialize the fragment. If u have it as a <fragment ... /> in XML, it won't call the onCreateView again. Wasted my 30 minutes to figure this out.
Here what i did and it worked for me i use firebase and when user is logIn i wanted to refresh current Fragment first you will need to requer context from activity because fragment dont have a way to get context unless you set it from Activity or context here is the code i used and worked in kotlin language i think you could use the same in java class
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
val context = requireActivity()
if (auth.currentUser != null) {
if (isVisibleToUser){
context.supportFragmentManager.beginTransaction().detach(this).attach(this).commit()
}
}
}
getActivity().getSupportFragmentManager().beginTransaction().replace(GeneralInfo.this.getId(), new GeneralInfo()).commit();
GeneralInfo it's my Fragment class GeneralInfo.java
I put it as a method in the fragment class:
public void Reload(){
getActivity().getSupportFragmentManager().beginTransaction().replace(LogActivity.this.getId(), new LogActivity()).commit();
}
Use a ContentProvider and load you data using a 'CursorLoader'. With this architecture your data will be automatically reloaded on database changes. Use third-party frameworks for your ContentProvider - you don't really want to implement it by yourself...
I had the same issue but none of the above worked for mine. either there was a backstack problem (after loading when user pressed back it would to go the same fragment again) or it didnt call the onCreaetView
finally i did this:
public void transactFragment(Fragment fragment, boolean reload) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
if (reload) {
getSupportFragmentManager().popBackStack();
}
transaction.replace(R.id.main_activity_frame_layout, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
good point is you dont need the tag or id of the fragment either.
if you want to reload
Make use of onResume method... both on the fragment activity and the activity holding the fragment.
For example with TabLayout: just implement OnTabSelectedListener. To reload the page, you may use implement SwipeRefreshLayout.OnRefreshListener i.e. public class YourFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
the onRefresh() method will be #Override from the interface i.e.:
#Override
public void onRefresh() {
loadData();
}
Here's the layout:
<com.google.android.material.tabs.TabLayout
android:id="#+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimaryLighter"
app:tabGravity="fill"
app:tabIndicatorColor="#color/white"
app:tabMode="fixed"
app:tabSelectedTextColor="#color/colorTextPrimary"
app:tabTextColor="#color/colorTextDisable" />
Code in your activity
TabLayout tabLayout = (TabLayout) findViewById(R.id.tablayout);
tabLayout.setupWithViewPager(viewPager);
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
if (tab.getPosition() == 0) {
yourFragment1.onRefresh();
} else if (tab.getPosition() == 1) {
yourFragment2.onRefresh();
}
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
// Reload current fragment
Fragment frag = new Order();
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.fragment_home, frag).commit();
None of these answers worked for me so I might as well post my solution if anyone still has problems with this. This solution works only if you are using the Navigation component.
Go to your navigation graph and find the fragment you want to refresh. Create an action from that fragment to itself. Now you can call that action inside that fragment like so.
private void refreshFragment(){
// This method refreshes the fragment
NavHostFragment.findNavController(FirstFragment.this)
.navigate(R.id.action_FirstFragment_self);
}
Below code reloads the current fragment onClick of button from Parent Activity.
layoutNews.setOnClickListener(v -> {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragNews);
ft.detach(fragNews);
ft.attach(fragNews);
ft.commit();
});
If you are in a fragment then use:
findNavController().run {
popBackStack()
navigate(R.id.your_fragment)
}
Easiest way
make a public static method containing viewpager.setAdapter
make adapter and viewpager static
public static void refreshFragments(){
viewPager.setAdapter(adapter);
}
call anywhere, any activity, any fragment.
MainActivity.refreshFragments();
protected void onResume() {
super.onResume();
viewPagerAdapter.notifyDataSetChanged();
}
Do write viewpagerAdapter.notifyDataSetChanged(); in onResume() in MainActivity.
Good Luck :)

Show hide fragment in android

I am developing application which contains 2 fragments and i want to show hide according to my need. Following code has simple example of my problem.
This simple Fragmentactivity contains 1 button and one listfragment.
This simple example works flawless. but i am not satisfied with show hide fragment. If you remove layout.setVisibility(View.GONE); from the code then ft.hide(f); will not hide fragment. In fact we are not hiding fragment we are hiding container.
My Question is, IS this a way to show hide fragments? If not then please explain with tested example How to hide and show Fragments because lots of people are facing this problem.
public class MainActivity extends FragmentActivity implements OnClickListener {
Fragment1 f;
Button b;
LinearLayout layout;
Fragment myf;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.button1);
layout = (LinearLayout) findViewById(R.id.ll);
f = new Fragment1();
}
#Override
public void onClick(View v) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);
if (f.isHidden()) {
ft.show(f);
layout.setVisibility(View.VISIBLE);
b.setText("Hide");
} else {
ft.hide(f);
b.setText("Show");
layout.setVisibility(View.GONE);
}
ft.commit();
// TODO Auto-generated method stub
}
Don't mess with the visibility flags of the container - FragmentTransaction.hide/show does that internally for you.
So the correct way to do this is:
FragmentManager fm = getFragmentManager();
fm.beginTransaction()
.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out)
.show(somefrag)
.commit();
OR if you are using android.support.v4.app.Fragment
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.show(somefrag)
.commit();
In addittion, you can do in a Fragment (for example when getting server data failed):
getView().setVisibility(View.GONE);
Hi you do it by using this approach, all fragments will remain in the container once added initially and then we are simply revealing the desired fragment and hiding the others within the container.
// Within an activity
private FragmentA fragmentA;
private FragmentB fragmentB;
private FragmentC fragmentC;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
fragmentA = FragmentA.newInstance("foo");
fragmentB = FragmentB.newInstance("bar");
fragmentC = FragmentC.newInstance("baz");
}
}
// Replace the switch method
protected void displayFragmentA() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (fragmentA.isAdded()) { // if the fragment is already in container
ft.show(fragmentA);
} else { // fragment needs to be added to frame container
ft.add(R.id.flContainer, fragmentA, "A");
}
// Hide fragment B
if (fragmentB.isAdded()) { ft.hide(fragmentB); }
// Hide fragment C
if (fragmentC.isAdded()) { ft.hide(fragmentC); }
// Commit changes
ft.commit();
}
Please see https://github.com/codepath/android_guides/wiki/Creating-and-Using-Fragments for more info. I hope I get to help anyone. Even if it this is an old question.
public void showHideFragment(final Fragment fragment){
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(android.R.animator.fade_in,
android.R.animator.fade_out);
if (fragment.isHidden()) {
ft.show(fragment);
Log.d("hidden","Show");
} else {
ft.hide(fragment);
Log.d("Shown","Hide");
}
ft.commit();
}
Try this:
MapFragment mapFragment = (MapFragment)getFragmentManager().findFragmentById(R.id.mapview);
mapFragment.getView().setVisibility(View.GONE);
I may be way way too late but it could help someone in the future.
This answer is a modification to mangu23 answer
I only added a for loop to avoid repetition and to easily add more fragments without boilerplate code.
We first need a list of the fragments that should be displayed
public class MainActivity extends AppCompatActivity{
//...
List<Fragment> fragmentList = new ArrayList<>();
}
Then we need to fill it with our fragments
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
HomeFragment homeFragment = new HomeFragment();
MessagesFragment messagesFragment = new MessagesFragment();
UserFragment userFragment = new UserFragment();
FavoriteFragment favoriteFragment = new FavoriteFragment();
MapFragment mapFragment = new MapFragment();
fragmentList.add(homeFragment);
fragmentList.add(messagesFragment);
fragmentList.add(userFragment);
fragmentList.add(favoriteFragment);
fragmentList.add(mapFragment);
}
And we need a way to know which fragment were selected from the list, so we need getFragmentIndex function
private int getFragmentIndex(Fragment fragment) {
int index = -1;
for (int i = 0; i < fragmentList.size(); i++) {
if (fragment.hashCode() == fragmentList.get(i).hashCode()){
return i;
}
}
return index;
}
And finally, the displayFragment method will like this:
private void displayFragment(Fragment fragment) {
int index = getFragmentIndex(fragment);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (fragment.isAdded()) { // if the fragment is already in container
transaction.show(fragment);
} else { // fragment needs to be added to frame container
transaction.add(R.id.placeholder, fragment);
}
// hiding the other fragments
for (int i = 0; i < fragmentList.size(); i++) {
if (fragmentList.get(i).isAdded() && i != index) {
transaction.hide(fragmentList.get(i));
}
}
transaction.commit();
}
In this way, we can call displayFragment(homeFragment) for example.
This will automatically show the HomeFragment and hide any other fragment in the list.
This solution allows you to append more fragments to the fragmentList without having to repeat the if statements in the old displayFragment version.
I hope someone will find this useful.
From my code, comparing to above solution, the simplest way is to define a layout which contains the fragment, then you could hide or unhide the fragment by controlling the layout attribute which is align with the general way of view. No additional code needed in this case and the additional deployment attributes of the fragment could be moved to the outer layout.
<LinearLayout style="#style/StHorizontalLinearView"
>
<fragment
android:layout_width="match_parent"
android:layout_height="390dp"
android:layout_alignParentTop="true"
/>
</LinearLayout>
final Fragment fragment1 = new fragment1();
final Fragment fragment2 = new fragment2();
final FragmentManager fm = getSupportFragmentManager();
Fragment active = fragment1;
In onCreate, after setContentView, i hid two fragments and committed them to the fragment manager, but i didn't hide the first fragment that will serve as home.
fm.beginTransaction().add(R.id.main_container, fragment2, "2").hide(fragment2).commit();
fm.beginTransaction().add(R.id.main_container,fragment1, "1").commit();
#Override
public void onClick(View v) {
Fragment another = fragment1;
if(active==fragment1){
another = fragment2;
}
fm.beginTransaction().hide(active).show(another).commit();
active = another;
}
Ref : https://medium.com/#oluwabukunmi.aluko/bottom-navigation-view-with-fragments-a074bfd08711
This worked for me
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if(tag.equalsIgnoreCase("dashboard")){
DashboardFragment dashboardFragment = (DashboardFragment)
fragmentManager.findFragmentByTag("dashboard");
if(dashboardFragment!=null) ft.show(dashboardFragment);
ShowcaseFragment showcaseFragment = (ShowcaseFragment)
fragmentManager.findFragmentByTag("showcase");
if(showcaseFragment!=null) ft.hide(showcaseFragment);
} else if(tag.equalsIgnoreCase("showcase")){
DashboardFragment dashboardFragment = (DashboardFragment)
fragmentManager.findFragmentByTag("dashboard");
if(dashboardFragment!=null) ft.hide(dashboardFragment);
ShowcaseFragment showcaseFragment = (ShowcaseFragment)
fragmentManager.findFragmentByTag("showcase");
if(showcaseFragment!=null) ft.show(showcaseFragment);
}
ft.commit();
the answers here are correct and i liked #Jyo the Whiff idea of a show and hide fragment implementation except the way he has it currently would hide the fragment on the first run so i added a slight change in that i added the isAdded check and show the fragment if its not already
public void showHideCardPreview(int id) {
FragmentManager fm = getSupportFragmentManager();
Bundle b = new Bundle();
b.putInt(Constants.CARD, id);
cardPreviewFragment.setArguments(b);
FragmentTransaction ft = fm.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
if (!cardPreviewFragment.isAdded()){
ft.add(R.id.full_screen_container, cardPreviewFragment);
ft.show(cardPreviewFragment);
} else {
if (cardPreviewFragment.isHidden()) {
Log.d(TAG,"++++++++++++++++++++ show");
ft.show(cardPreviewFragment);
} else {
Log.d(TAG,"++++++++++++++++++++ hide");
ft.hide(cardPreviewFragment);
}
}
ft.commit();
}

get the latest fragment in backstack

How can I get the latest fragment instance added in backstack (if I do not know the fragment tag & id)?
FragmentManager fragManager = activity.getSupportFragmentManager();
FragmentTransaction fragTransacion = fragMgr.beginTransaction();
/****After add , replace fragments
(some of the fragments are add to backstack , some are not)***/
//HERE, How can I get the latest added fragment from backstack ??
You can use the getName() method of FragmentManager.BackStackEntry which was introduced in API level 14. This method will return a tag which was the one you used when you added the Fragment to the backstack with addTobackStack(tag).
int index = getActivity().getFragmentManager().getBackStackEntryCount() - 1
FragmentManager.BackStackEntry backEntry = getFragmentManager().getBackStackEntryAt(index);
String tag = backEntry.getName();
Fragment fragment = getFragmentManager().findFragmentByTag(tag);
You need to make sure that you added the fragment to the backstack like this:
fragmentTransaction.addToBackStack(tag);
FragmentManager.findFragmentById(fragmentsContainerId)
function returns link to top Fragment in backstack. Usage example:
fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
Fragment fr = fragmentManager.findFragmentById(R.id.fragmentsContainer);
if(fr!=null){
Log.e("fragment=", fr.getClass().getSimpleName());
}
}
});
I personnaly tried many of those solutions and ended up with this working solution:
Add this utility method that will be used several times below to get the number of fragments in your backstack:
protected int getFragmentCount() {
return getSupportFragmentManager().getBackStackEntryCount();
}
Then, when you add/replace your fragment using FragmentTransaction method, generate a unique tag to your fragment (e.g.: by using the number of fragments in your stack):
getSupportFragmentManager().beginTransaction().add(yourContainerId, yourFragment, Integer.toString(getFragmentCount()));
Finally, you can find any of your fragments in your backstack with this method:
private Fragment getFragmentAt(int index) {
return getFragmentCount() > 0 ? getSupportFragmentManager().findFragmentByTag(Integer.toString(index)) : null;
}
Therefore, fetching the top fragment in your backstack can be easily achieved by calling:
protected Fragment getCurrentFragment() {
return getFragmentAt(getFragmentCount() - 1);
}
Hope this helps!
Kotlin
// In activities
activity.supportFragmentManager.fragments.lastOrNull()
// In fragments
fragment.childFragmentManager.fragments.lastOrNull()
this helper method get fragment from top of stack:
public Fragment getTopFragment() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
return null;
}
String fragmentTag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
return getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
There is a list of fragments in the fragmentMananger. Be aware that removing a fragment, does not make the list size decrease (the fragment entry just turn to null). Therefore, a valid solution would be:
public Fragment getTopFragment() {
List<Fragment> fragentList = fragmentManager.getFragments();
Fragment top = null;
for (int i = fragentList.size() -1; i>=0 ; i--) {
top = (Fragment) fragentList.get(i);
if (top != null) {
return top;
}
}
return top;
}
The answer given by deepak goel does not work for me because I always get null from entry.getName();
What I do is to set a Tag to the fragment this way:
ft.add(R.id.fragment_container, fragmentIn, FRAGMENT_TAG);
Where ft is my fragment transaction and FRAGMENT_TAG is the tag. Then I use this code to get the fragment:
Fragment prev_fragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);
Just took #roghayeh hosseini (correct) answer and made it in Kotlin for those here in 2017 :)
fun getTopFragment(): Fragment? {
supportFragmentManager.run {
return when (backStackEntryCount) {
0 -> null
else -> findFragmentByTag(getBackStackEntryAt(backStackEntryCount - 1).name)
}
}
}
*This should be called from inside an Activity.
Enjoy :)
Looks like something has changed for the better, because code below works perfectly for me, but I didn't find it in already provided answers.
Kotlin:
supportFragmentManager.fragments[supportFragmentManager.fragments.size - 1]
Java:
getSupportFragmentManager().getFragments()
.get(getSupportFragmentManager().getFragments().size() - 1)
you can use getBackStackEntryAt(). In order to know how many entry the activity holds in the backstack you can use getBackStackEntryCount()
int lastFragmentCount = getBackStackEntryCount() - 1;
I will add something to Deepak Goel's answer since a lot of people, me included, were getting a null by using his method. Apparently to make the tag work when you add a fragment to the backstack you should be doing it like this:
getSupportFragmentManager.beginTransaction().replace(R.id.container_id,FragmentName,TAG_NAME).addToBackStack(TAG_NAME).commit();
You need to add the same tag twice.
I would have commented but i don't have 50 reputation.
Keep your own back stack: myBackStack. As you Add a fragment to the FragmentManager, also add it to myBackStack. In onBackStackChanged() pop from myBackStack when its length is greater than getBackStackEntryCount.
If you use addToBackStack(), you can use following code.
List<Fragment> fragments = fragmentManager.getFragments();
activeFragment = fragments.get(fragments.size() - 1);
Actually there's no latest fragment added to the stack because you can add several or fragments to the stack in a single transaction or just remove fragments without adding a new one.
If you really want to have a stack of fragments and to be able to access a fragment by its index in the stack, you'd better have an abstraction layer over the FragmentManager and its backstack. Here's how you can do it:
public class FragmentStackManager {
private final FragmentManager fragmentManager;
private final int containerId;
private final List<Fragment> fragments = new ArrayList<>();
public FragmentStackManager(final FragmentManager fragmentManager,
final int containerId) {
this.fragmentManager = fragmentManager;
this.containerId = containerId;
}
public Parcelable saveState() {
final Bundle state = new Bundle(fragments.size());
for (int i = 0, count = fragments.size(); i < count; ++i) {
fragmentManager.putFragment(state, Integer.toString(i), fragments.get(i));
}
return state;
}
public void restoreState(final Parcelable state) {
if (state instanceof Bundle) {
final Bundle bundle = (Bundle) state;
int index = 0;
while (true) {
final Fragment fragment =
fragmentManager.getFragment(bundle, Integer.toString(index));
if (fragment == null) {
break;
}
fragments.add(fragment);
index += 1;
}
}
}
public void replace(final Fragment fragment) {
fragmentManager.popBackStackImmediate(
null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragmentManager.beginTransaction()
.replace(containerId, fragment)
.addToBackStack(null)
.commit();
fragmentManager.executePendingTransactions();
fragments.clear();
fragments.add(fragment);
}
public void push(final Fragment fragment) {
fragmentManager
.beginTransaction()
.replace(containerId, fragment)
.addToBackStack(null)
.commit();
fragmentManager.executePendingTransactions();
fragments.add(fragment);
}
public boolean pop() {
if (isEmpty()) {
return false;
}
fragmentManager.popBackStackImmediate();
fragments.remove(fragments.size() - 1);
return true;
}
public boolean isEmpty() {
return fragments.isEmpty();
}
public int size() {
return fragments.size();
}
public Fragment getFragment(final int index) {
return fragments.get(index);
}
}
Now instead of adding and removing fragments by calling FragmentManager directly, you should use push(), replace(), and pop() methods of FragmentStackManager. And you will be able to access the topmost fragment by just calling stack.get(stack.size() - 1).
But if you like hacks, I have to other ways of doing similar things. The only thing I have to mention is that these hacks will work only with support fragments.
The first hack is just to get all active fragments added to the fragment manager. If you just replace fragments one by one and pop the from the stack this method will return the topmost fragment:
public class BackStackHelper {
public static List<Fragment> getTopFragments(
final FragmentManager fragmentManager) {
final List<Fragment> fragments = fragmentManager.getFragments();
final List<Fragment> topFragments = new ArrayList<>();
for (final Fragment fragment : fragments) {
if (fragment != null && fragment.isResumed()) {
topFragments.add(fragment);
}
}
return topFragments;
}
}
The second approach is event more hacky and allows you to get all fragments added in the last transaction for which addToBackStack has been called:
package android.support.v4.app;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BackStackHelper {
public static List<Fragment> getTopFragments(
final FragmentManager fragmentManager) {
if (fragmentManager.getBackStackEntryCount() == 0) {
return Collections.emptyList();
}
final List<Fragment> fragments = new ArrayList<>();
final int count = fragmentManager.getBackStackEntryCount();
final BackStackRecord record =
(BackStackRecord) fragmentManager.getBackStackEntryAt(count - 1);
BackStackRecord.Op op = record.mHead;
while (op != null) {
switch (op.cmd) {
case BackStackRecord.OP_ADD:
case BackStackRecord.OP_REPLACE:
case BackStackRecord.OP_SHOW:
case BackStackRecord.OP_ATTACH:
fragments.add(op.fragment);
}
op = op.next;
}
return fragments;
}
}
Please notice that in this case you have to put this class into android.support.v4.app package.
Or you may just add a tag when adding fragments corresponding to their content and use simple static String field (also you may save it in activity instance bundle in onSaveInstanceState(Bundle) method) to hold last added fragment tag and get this fragment byTag() at any time you need...
The highest (Deepak Goel) answer didn't work well for me. Somehow the tag wasn't added properly.
I ended up just sending the ID of the fragment through the flow (using intents) and retrieving it directly from fragment manager.
Kotlin Developers can use this to get the current fragment:
supportFragmentManager.addOnBackStackChangedListener {
val myFragment = supportFragmentManager.fragments.last()
if (null != myFragment && myFragment is HomeFragment) {
//HomeFragment is visible or currently loaded
} else {
//your code
}
}

How do I get the currently displayed fragment?

I am playing with fragments in Android.
I know I can change a fragment by using the following code:
FragmentManager fragMgr = getSupportFragmentManager();
FragmentTransaction fragTrans = fragMgr.beginTransaction();
MyFragment myFragment = new MyFragment(); //my custom fragment
fragTrans.replace(android.R.id.content, myFragment);
fragTrans.addToBackStack(null);
fragTrans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
fragTrans.commit();
My question is, in a Java file, how can I get the currently displayed Fragment instance?
When you add the fragment in your transaction you should use a tag.
fragTrans.replace(android.R.id.content, myFragment, "MY_FRAGMENT");
...and later if you want to check if the fragment is visible:
MyFragment myFragment = (MyFragment)getSupportFragmentManager().findFragmentByTag("MY_FRAGMENT");
if (myFragment != null && myFragment.isVisible()) {
// add your code here
}
See also http://developer.android.com/reference/android/app/Fragment.html
I know it's an old post, but was having trouble with it previously too. Found a solution which was to do this in the onBackStackChanged() listening function
#Override
public void onBackPressed() {
super.onBackPressed();
Fragment f = getActivity().getFragmentManager().findFragmentById(R.id.fragment_container);
if(f instanceof CustomFragmentClass)
// do something with f
((CustomFragmentClass) f).doSomething();
}
This worked for me as I didn't want to iterate through every fragment I have to find one that is visible.
Here is my solution which I find handy for low fragment scenarios
public Fragment getVisibleFragment(){
FragmentManager fragmentManager = MainActivity.this.getSupportFragmentManager();
List<Fragment> fragments = fragmentManager.getFragments();
if(fragments != null){
for(Fragment fragment : fragments){
if(fragment != null && fragment.isVisible())
return fragment;
}
}
return null;
}
Every time when you show fragment you must put it tag into backstack:
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_ENTER_MASK);
ft.add(R.id.primaryLayout, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
And then when you need to get current fragment you may use this method:
public BaseFragment getActiveFragment() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
return null;
}
String tag = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1).getName();
return (BaseFragment) getSupportFragmentManager().findFragmentByTag(tag);
}
Kotlin way;
val currentFragment = supportFragmentManager.fragments.last()
What I am using to find current displaying fragment is in below code. It is simple and it works for me by now. It runs in the activity which holds the fragments
FragmentManager fragManager = this.getSupportFragmentManager();
int count = this.getSupportFragmentManager().getBackStackEntryCount();
Fragment frag = fragManager.getFragments().get(count>0?count-1:count);
The reactive way:
Observable.from(getSupportFragmentManager().getFragments())
.filter(fragment -> fragment.isVisible())
.subscribe(fragment1 -> {
// Do something with it
}, throwable1 -> {
//
});
My method is based on try / catch like this :
MyFragment viewer = null;
if(getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT) instanceOf MyFragment){
viewer = (MyFragment) getFragmentManager().findFragmentByTag(MY_TAG_FRAGMENT);
}
But there may be a better way ...
If you are using the AndroidX Navigation:
val currentFragment = findNavController(R.id.your_navhost)?.currentDestination
For more info on this navigation component:
https://developer.android.com/guide/navigation/navigation-getting-started
Well, this question got lots of views and attention but still did not contained
the easiest solution from my end - to use getFragments().
List fragments = getSupportFragmentManager().getFragments();
mCurrentFragment = fragments.get(fragments.size() - 1);
You can query which fragment is loaded into your Activities content frame, and retrieve the fragment class, or fragment 'simple name' (as a string).
public String getCurrentFragment(){
return activity.getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();
}
Usage:
Log.d(TAG, getCurrentFragment());
Outputs:
D/MainActivity: FragOne
If get here and you are using Kotlin:
var fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
R.id.fragment_container is the id where the fragment is presenting on their activity
Or if you want a nicer solution:
supportFragmentManager.findFragmentById(R.id.content_main)?.let {
// the fragment exists
if (it is FooFragment) {
// The presented fragment is FooFragment type
}
}
It's a bit late, But for anyone who is interested :
If you know the index of the your desired fragment in FragmentManager just get a reference to it and check for isMenuVisible() function! here :
getSupportFragmentManager().getFragments().get(0).isMenuVisible()
If true Its visible to user and so on!
1)
ft.replace(R.id.content_frame, fragment, **tag**).commit();
2)
FragmentManager fragmentManager = getSupportFragmentManager();
Fragment currentFragment = fragmentManager.findFragmentById(R.id.content_frame);
3)
if (currentFragment.getTag().equals(**"Fragment_Main"**))
{
//Do something
}
else
if (currentFragment.getTag().equals(**"Fragment_DM"**))
{
//Do something
}
There's a method called findFragmentById() in SupportFragmentManager. I use it in the activity container like :
public Fragment currentFragment(){
return getSupportFragmentManager().findFragmentById(R.id.activity_newsfeed_frame);
}
That's how to get your current Fragment. If you have custom Fragment and need to check what Fragment it is, I normally use instanceof :
if (currentFragment() instanceof MyFrag){
// Do something here
}
This should work -
val visibleFragment = supportFragmentManager.fragments.findLast { fgm -> fgm.isVisible }
Timber.d("backStackIterator: visibleFragment: $visibleFragment")
Inspired by Tainy's answer, here is my two cents. Little modified from most other implementations.
private Fragment getCurrentFragment() {
FragmentManager fragmentManager = myActivity.getSupportFragmentManager();
int stackCount = fragmentManager.getBackStackEntryCount();
if( fragmentManager.getFragments() != null ) return fragmentManager.getFragments().get( stackCount > 0 ? stackCount-1 : stackCount );
else return null;
}
Replace "myActivity" with "this" if it is your current activity or use reference to your activity.
This is simple way to get current fragment..
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override public void onBackStackChanged() {
currentFragment = fragmentManager.findFragmentById(R.id.content);
if (currentFragment != null && (currentFragment instanceof LoginScreenFragment)) {
logout.setVisibility(View.GONE);
} else {
logout.setVisibility(View.VISIBLE);
}
}
});
Checkout this solution. It worked for me to get the current Fragment.
if(getSupportFragmentManager().getBackStackEntryCount() > 0){
android.support.v4.app.Fragment f =
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
if(f instanceof ProfileFragment){
Log.d(TAG, "Profile Fragment");
}else if(f instanceof SavedLocationsFragment){
Log.d(TAG, "SavedLocations Fragment");
}else if(f instanceof AddLocationFragment){
Log.d(TAG, "Add Locations Fragment");
}
it's so simple, not that much code you need to write
yourFragment.isAdded()
or
yourFragment.isVisible();
I prefer isAdded(),both of them return boolean value use it in if condition and must initialize your fragment in onCreate() otherwise you will get null point exception.
None of the above 30 answers fully worked for me. But here is the answer that worked:
Using Kotlin, when using Navigation Component:
fun currentVisibleFragment(): Fragment? {
return supportFragmentManager.fragments.first()?.getChildFragmentManager()?.getFragments()?.get(0)
}
Sev's answer works for when you hit the back button or otherwise change the backstack.
I did something slightly different, though. I have a backstack change listener setup on a base Fragment and its derived fragments and this code is in the listener:
Fragment f = getActivity().getSupportFragmentManager().findFragmentById(R.id.container);
if (f.getClass().equals(getClass())) {
// On back button, or popBackStack(),
// the fragment that's becoming visible executes here,
// but not the one being popped, or others on the back stack
// So, for my case, I can change action bar bg color per fragment
}
Easy way to do that :
Fragment fr=getSupportFragmentManager().findFragmentById(R.id.fragment_container);
String fragmentName = fr.getClass().getSimpleName();
I had to do this very recently
public Fragment getCurrentFragment() {
return fragmentManager.findFragmentById(R.id.container);
}
and finaly i got last fragment on this container.
final FragmentManager fm=this.getSupportFragmentManager();
final Fragment fragment=fm.findFragmentByTag("MY_FRAGMENT");
if(fragment != null && fragment.isVisible()){
Log.i("TAG","my fragment is visible");
}
else{
Log.i("TAG","my fragment is not visible");
}
If you are getting the current instance of Fragment from the parent activity you can just
findFragmentByID(R.id.container);
This actually get's the current instance of fragment that's populated on the view. I had the same issue. I had to load the same fragment twice keeping one on backstack.
The following method doesn't work. It just gets a Fragment that has the tag. Don't waste your time on this method. I am sure it has it's uses but to get the most recent version of the same Fragment is not one of them.
findFragmentByTag()
Kotlin safer way than exposed here
supportFragmentManager.fragments.lastOrNull()?.let { currentFragment ->
//Do something here
}
This is work for me. I hope this will hepl someone.
FragmentManager fragmentManager = this.getSupportFragmentManager();
String tag = fragmentManager
.getBackStackEntryAt(
fragmentManager
.getBackStackEntryCount() - 1)
.getName();
Log.d("This is your Top Fragment name: ", ""+tag);
I found findFragmentByTag isn't that convenient. If you have String currentFragmentTag in your Activity or parent Fragment, you need to save it in onSaveInstanceState and restore it in onCreate. Even if you do so, when the Activity recreated, onAttachFragment will called before onCreate, so you can't use currentFragmentTag in onAttachFragment(eg. update some views based on currentFragmentTag), because it's might not yet restored.
I use the following code:
Fragment getCurrentFragment() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if(fragments.isEmpty()) {
return null;
}
return fragments.get(fragments.size()-1);
}
The document of FragmentManager state that
The order of the fragments in the list is the order in which they were added or attached.
When you need to do stuff based on current fragment type, just use getCurrentFragment() instance of MyFragment instead of currentFragmentTag.equals("my_fragment_tag").
Note that getCurrentFragment() in onAttachFragment will not get the attaching Fragment, but the previous attached one.
getSupportFragmentManager().findFragmentById(R.id.content_frame).getClass().getSimpleName();
Well, I guess this is the most straight forward answer to this question.
I hope this helps.

Categories

Resources