Reputation: 14571
Before trying the Navigation component I used to manually do fragment transactions and used the fragment tag in order to fetch the current fragment.
val fragment:MyFragment = supportFragmentManager.findFragmentByTag(tag):MyFragment
Now in my main activity layout I have something like:
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/nav_host"
app:navGraph= "@navigation/nav_item"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost= "true"
/>
How can I retrieve the current displayed fragment by the Navigation component? Doing
supportFragmentManager.findFragmentById(R.id.nav_host)
returns a NavHostFragment
and I want to retrieve my shown 'MyFragment`.
Thank you.
Upvotes: 173
Views: 147590
Reputation: 2176
To communicate between Activity and fragment it is better and easier now to use a shared viewmodel.
just pass activity context while creating the viemmodel instance both in activity and fragment. Look at the code below
In Activity
SharedViewModel sharedViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
sharedViewModel = new ViewModelProvider(this).get(SharedViewModel.class);
// ...
}
In Fragment
SharedViewModel sharedViewModel;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
// ...
}
Upvotes: 1
Reputation: 617
private fun checkIfFragmentVisible(): Boolean {
findNavController().currentDestination?.let { navDestination ->
if (navDestination is FragmentNavigator.Destination)
return navDestination.className == myFragment().javaClass.name
if (navDestination is DialogFragmentNavigator.Destination)
return navDestination.className == myFragment().javaClass.name
}
return false
}
Upvotes: 0
Reputation: 21
You should try get fragmentHost
and then get its first child
then instanceof CustomFragment
.
Here example
@Override
public void onBackPressed() {
// get parent host
Fragment fragmentHost = getSupportFragmentManager().findFragmentById(
R.id.frame_container);
// get first child fragment
Fragment fragment = fragmentHost.getChildFragmentManager()
.getFragments().get(0);
if (fragment instanceof AccountFragment) {
Log.d(STRING.TAG, "onBackPressed: home");
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
return;
}
this.doubleBackToExitPressedOnce = true;
FancyToast.makeText(this, STRING.message_exit,
FancyToast.LENGTH_SHORT, FancyToast.INFO, false)
.show();
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, STRING.delayMillis);
} else {
Log.d(STRING.TAG, "onBackPressed: not home");
super.onBackPressed();
}
}
Upvotes: 1
Reputation: 382
I did a bit different in my app than all these answers
I created global variable in class myClass (myClass.kt)
var currentFragmentName: String = "defaultValue"
When in Fragment I update it (TagsFragment.kt)
currentFragmentName = "tagsFragment"
And in my case in back button (in parent activity of TagsFragment.kt)
Log.d(TAG, myClass.currentFragmentName) val homeFragment = HomeFragment() if(InTorry.currentFragmentName=="tagsFragment"){ setCurrentFragment(homeFragment,"fragment_tag_home") }
Upvotes: 0
Reputation: 21
Kotlin version code for get currently active fragment in Navigation Graph
fun getCurrentFragmentInstance(activity: HomeActivity): Fragment? {
val navHostFragment =
activity.supportFragmentManager.primaryNavigationFragment as NavHostFragment?
val fragmentManager: FragmentManager = navHostFragment!!.childFragmentManager
return fragmentManager.primaryNavigationFragment
}
Upvotes: 0
Reputation: 789
Add the following method in your Activity
class:
private Fragment getCurrentFragment() {
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager()
.findFragmentById(R.id.nav_host);
if (navHostFragment != null) return navHostFragment.getChildFragmentManager()
.getPrimaryNavigationFragment();
return null;
}
That's the shortest and cleanest solution for your problem.
Hope it helps!
Upvotes: 1
Reputation: 17404
My requirement is to get the current visible fragment from Parent activity,my solution is
private Fragment getCurrentVisibleFragment() {
NavHostFragment navHostFragment = (NavHostFragment)getSupportFragmentManager().getPrimaryNavigationFragment();
FragmentManager fragmentManager = navHostFragment.getChildFragmentManager();
Fragment fragment = fragmentManager.getPrimaryNavigationFragment();
if(fragment instanceof Fragment ){
return fragment ;
}
return null;
}
This may help some one with same problem.
Upvotes: 18
Reputation: 116
create extension function on Fragment Manager
inline fun <reified T : Fragment> FragmentManager.findNavFragment(hostId: Int): T? {
val navHostFragment = findFragmentById(hostId)
return navHostFragment?.childFragmentManager?.fragments?.findLast {
it is T
} as T?
}
Now simply use it by giving id of the hosting fragment and get the specified fragment
val myFragment: MyFragment? = supportFragmentManager.findNavFragment<MyFragment>(R.id.nav_host_id)
Upvotes: 2
Reputation: 156
Within your activity, hosting the NavHostFragment we can write the following piece of code to fetch the instance of the currently displayed fragment
Fragment fragment = myNavHostFragment.getChildFragmentManager().findFragmentById(R.id.navHostFragmentId)
if(fragment instanceOf MyFragment) {
//Write your code here
}
Here R.id.navHostFragmentId is the resId for the NavHostFragment within your activity xml
Upvotes: 3
Reputation: 149
Here is my solution for java
NavHostFragment navHostFragment= (NavHostFragment) getSupportFragmentManager().getFragments().get(0);
MyFragment fragment = (MyFragment) navHostFragment.getChildFragmentManager().getFragments().get(0);
fragment.doSomething();
Upvotes: 2
Reputation: 440
Using navigation components, I got the current displayed fragment using this line of code:
val fragment = parentFragmentManager.primaryNavigationFragment
Upvotes: 5
Reputation: 441
First, you get the current fragment by id, then you can find the fragment, depending on that id.
int id = navController.getCurrentDestination().getId();
Fragment fragment = getSupportFragmentManager().findFragmentById(id);
Upvotes: 8
Reputation: 1919
val fragment: YourFragment? = yourNavHost.findFragment()
Note: findFragment
extension function is located in androidx.fragment.app
package, and it's generic function
Upvotes: 1
Reputation: 943
this might be late but for anyone who's still looking
val currentFragment = NavHostFragment.findNavController(nav_host_fragment).currentDestination?.id
then you can do something like
if(currentFragment == R.id.myFragment){
//do something
}
note that this is for kotlin, java code should be almost the same
Upvotes: 23
Reputation: 1052
The best way I could figure out with 1 fragment, Kotlin, Navigation usage:
On your layout file add the tag: "android:tag="main_fragment_tag""
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/nav_host"
app:navGraph= "@navigation/nav_item"
android:tag="main_fragment_tag"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost= "true"
/>
On your Activity:
val navHostFragment = supportFragmentManager.findFragmentByTag("main_fragment_tag") as NavHostFragment
val mainFragment = navHostFragment.childFragmentManager.fragments[0] as MainFragment
mainFragment.mainFragmentMethod()
Upvotes: 2
Reputation: 427
Finally the working solution for those of you who are still searching Actually it is very simple and you can achieve this using callback.
follow these steps:
Create a listener inside the fragment you want to get the instance from activity onCreate()
public class HomeFragment extends Fragment {
private OnCreateFragment createLIstener;
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
createLIstener.onFragmentCreated(this);
View root = inflater.inflate(R.layout.fragment_home, container, false);
//findViews(root);
return root;
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.menu_main, menu);
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId()==R.id.action_show_filter){
//do something
}
return super.onOptionsItemSelected(item);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
createLIstener = (OnCreateFragment) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement OnArticleSelectedListener");
}
}
public interface OnCreateFragment{
void onFragmentCreated(Fragment f);
}
}
Implement your listener in the host Fragment/Activity
public class MainActivity extends AppCompatActivity implements HomeFragment.OnCreateFragment {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView navView = findViewById(R.id.nav_view);
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
R.id.navigation_home,
R. ----)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
NavigationUI.setupWithNavController(navView, navController);
}
@Override
public void onFragmentCreated(Fragment f) {
if (f!=null){
H.debug("fragment created listener: "+f.getId());
f.setHasOptionsMenu(true);
}else {
H.debug("fragment created listener: NULL");
}
}
}
And that is everything you need to do the job. Hop this help someone
Upvotes: 2
Reputation: 4118
As per @slhddn answer and comment this is how I'm using it and retrieving the fragment id from the nav_graph.xml file:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(findViewById(R.id.toolbar))
val navController = findNavController(this, R.id.nav_host_fragment)
ivSettingsCog.setOnClickListener {
if (navController.currentDestination?.id == R.id.updatesFragment) // Id as per set up on nav_graph.xml file
{
navController.navigate(R.id.action_updatesFragment_to_settingsFragment)
}
}
}
}
Upvotes: 5
Reputation: 1997
There is no way I can find to retrieve the current fragment instance. However, you can get the ID of lastly added fragment using the code below.
navController.currentDestination?.getId()
It returns the ID in navigation file. Hope this helps.
Upvotes: 93
Reputation: 336
this might be late but may help someone later.
if you are using nested navigations you can get id like this in Kotlin
val nav = Navigation.findNavController(requireActivity(), R.id.fragment_nav_host).currentDestination
and this is one of fragments in fragment_nav_host.xml
<fragment
android:id="@+id/sampleFragment"
android:name="com.app.sample.SampleFragment"
android:label="SampleFragment"
tools:layout="@layout/fragment_sample" />
and you can check all you need like this
if (nav.id == R.id.sampleFragment || nav.label == "SampleFragment"){}
Upvotes: 1
Reputation: 2511
The first fragment in navhost fragment is the current fragment
Fragment navHostFragment = getSupportFragmentManager().getPrimaryNavigationFragment();
if (navHostFragment != null)
{Fragment fragment = navHostFragment.getChildFragmentManager().getFragments().get(0);}
Upvotes: 2
Reputation: 489
This works for me
(navController.currentDestination as FragmentNavigator.Destination).className
It will return canonicalName
of your fragment
Upvotes: 0
Reputation: 4138
This code works from me
NavDestination current = NavHostFragment.findNavController(getSupportFragmentManager().getPrimaryNavigationFragment().getFragmentManager().getFragments().get(0)).getCurrentDestination();
switch (current.getId()) {
case R.id.navigation_saved:
// WRITE CODE
break;
}
Upvotes: 1
Reputation: 1546
This seems like the cleanest solution. Update: Changed extension function to property. Thanks Igor Wojda.
1. Create the following extension
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
val FragmentManager.currentNavigationFragment: Fragment?
get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
2. In Activity
with NavHostFragment
use it like this:
val currentFragment = supportFragmentManager.currentNavigationFragment
Upvotes: 36
Reputation: 2258
This solution will work in most situations Try this:
val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment?.parentFragment as MainFragment
or this:
val mainFragment = fragmentManager?.primaryNavigationFragment?.parentFragment as MainFragment
Upvotes: 0
Reputation: 592
Use addOnDestinationChangedListener
in activity having NavHostFragment
For Java
NavController navController= Navigation.findNavController(MainActivity.this,R.id.your_nav_host);
navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
Log.e(TAG, "onDestinationChanged: "+destination.getLabel());
}
});
For Kotlin
var navController :NavController=Navigation.findNavController(this, R.id.nav_host_fragment)
navController.addOnDestinationChangedListener { controller, destination, arguments ->
Log.e(TAG, "onDestinationChanged: "+destination.label);
}
Upvotes: 30
Reputation: 2057
From an Activity that uses NavHostFragment
, you can use the code below to retrieve the instance of the Active Fragment
.
val fragmentInstance = myNavHostFragment?.childFragmentManager?.primaryNavigationFragment
Upvotes: 3
Reputation: 5335
navController().currentDestination?.id
will give you your current Fragment
's id where
private fun navController() = Navigation.findNavController(this, R.id.navHostFragment)
this id is the id which you have given in your Navigation Graph XML
file under fragment
tag. You could also compare currentDestination.label
if you want.
Upvotes: 9
Reputation: 11
On Androidx, I have tried many methods for finding out required fragment from NavHostFragment
. Finally I could crack it with below method
public Fragment getFunctionalFragment (String tag_name)
{
NavHostFragment navHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
FragmentManager navHostManager = Objects.requireNonNull(navHostFragment).getChildFragmentManager();
Fragment fragment=null;
List fragment_list = navHostManager.getFragments();
for (int i=0; i < fragment_list.size() ; i ++ )
{
if ( fragment_list.get(i) instanceof HomeFragment && tag_name.equals("frg_home")) {
fragment = (HomeFragment) fragment_list.get(i);
break;
}
}
return fragment;
}
Upvotes: 1
Reputation: 11
If you need the instance of your fragment, you can go with:
(Activity) => supportFragmentManager.fragments.first().childFragmentManager.fragments.first()
It's very ugly but from there you can check if it's an instance of the fragment you want to play around with
Upvotes: 1
Reputation: 1204
Make :
• in some button in your fragment:
val navController = findNavController(this)
navController.popBackStack()
• In your Activity onBackPressed()
override fun onBackPressed() {
val navController = findNavController(R.id.nav_host_fragment)
val id = navController.currentDestination?.getId()
if (id == R.id.detailMovieFragment){
navController.popBackStack()
return
}
super.onBackPressed()
}
Upvotes: 2