I have two fragments; HomeFragment & NextFragment and I go to the next one with a button from the base fragment. Then via back press I want to go back to the first one, however I end up at the apps home screen. A solution
requireActivity().onBackPressedDispatcher
.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
findNavController().popBackStack()
}
})
was given here but it did not work. I am using ViewPager2 and saw that the home fragment is destroyed when I go to the next one. How can I solve the problem?
Related
private fun navBottomClick() {
bottomNavigationView?.setOnItemSelectedListener {
when(it.itemId){
R.id.workout ->{
val fragmentTransaction:FragmentTransaction = supportFragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.container,WorkoutFragment(),"WORKOUT")
//fragmentTransaction.addToBackStack("WORKOUT")
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
fragmentTransaction.commit()
}
R.id.steps ->{
intent = Intent(this,StepsActivity::class.java)
startActivity(intent)
}
}
true
}
}
override fun onBackPressed() {
super.onBackPressed()
}
}
When I pressed back, my app is closed. I want to make it go from a fragment to the main acitvity.
You have misunderstood the concept of Fragments and Activity . The issue you facing of the application getting close on navigating back from the fragment because it is the last fragment present in the stack .
Concept :
Basically , an Activity acts as an container for all of your Fragments . So , you create an activity and create a Fragment-Container / FrameLayout in that Activity wherein you assign the Fragments. So , Consider this example :
Here you can see, there are two fragments and both of them are placed in only one Activity . So this clarifies that Activity acts as an container for fragments .
What causes the Issue of Application being closed :
So what happens is when you navigate back from the last fragment , since it does not have anywhere to go back it closes the application .
Solution :
So if you want to get your Activity on navigating back on the last fragment to the Activity then , you need to override the popBackStack() method on the last Fragment and in there you need to disable the FragmentContainer / FrameLayout view, in this way you can get your activity back .
Recommended Solution : Move all the stuffs that you want to show at the end from your Activity to another Fragment and popBackStack() to that Fragment, doing such maintains the Single Activity principle .
You should have a popbackstack to send the screen correctly. Check if your fragment has implemented inside of this activity, if yes, really that will be closed.
Don't forget that fragment is inside of the one activity.
You need to un-comment this line
//fragmentTransaction.addToBackStack("WORKOUT")
then it will work as there is no stack maintained activity can't go back to previous fragment and will close the activity.
I am working on android application that contains five fragment on an activity, What I want is as the fragment 1 is opened and I back-press it comes to Main fragment and same as I press back-press from fragment 5 it also comes to Main fragment.
and When I press on Backpress from MainFragment, the App should Exit.
I have Gone through this link Link
and I have also added the Dispatcher but It not met my requirement.
Like I am always opening each fragment like this
private fun ShowQRCodeFragment() {
val newFragment: Fragment = QrCodeScanningFragment()
val transaction1: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction1.replace(R.id.frameLayout, newFragment)
transaction1.addToBackStack(null)
transaction1.commit()
}
Updated the transaction
private fun FunctionNewSettings() {
val newFragment: Fragment = CustomSettingsFragment()
val transaction1: FragmentTransaction = supportFragmentManager.beginTransaction()
transaction1.replace(R.id.frameLayout, newFragment)
transaction1.addToBackStack("namedata")
fragmentManager.popBackStack()
transaction1.commit()
}
You should use addToBackStack() while fragment transaction. This will allow you to go to the previous fragment on back-press.
For the app exit case, check if the current fragment is MainFragment with the help of fragment tag and calling fragmentmanager.popBackStack() or super.onBackPressed() accordingly.
In MainFragment, use
override fun onAttach(context: Context) {
super.onAttach(context)
val callback = object : OnBackPressedCallback(
true // default to enabled
) {
override fun handleOnBackPressed() {
requireActivity().finish()
}
}
requireActivity().onBackPressedDispatcher.addCallback(
this, // LifecycleOwner
callback
)
}
In another fragments, use
override fun onAttach(context: Context) {
super.onAttach(context)
val callback = object : OnBackPressedCallback(
true // default to enabled
) {
override fun handleOnBackPressed() {
for (i in 0 until (requireActivity() as FragmentActivity).supportFragmentManager.backStackEntryCount) {
activity.supportFragmentManager.popBackStack()
}
}
}
requireActivity().onBackPressedDispatcher.addCallback(
this, // LifecycleOwner
callback
)
}
if u want to go back to the previous fragment first use
addToBackStack()
and if you want to exit the app/activity by using onBackPressed from activity then in MainFragment use
getActivity().onBackPressed();
if you want to finish the activity from Fragment use
getActivity().finish();
You can also replace existing fragment when user clicks Back button using
fragmentTransaction.replace(int containerViewId, Fragment fragment, String tag)
Solution
Override onBackPressed() method inside your activity.
override fun onBackPressed() {
val count = supportFragmentManager.backStackEntryCount
if (count > 1) {
repeat(count - 1) { supportFragmentManager.popBackStack() }
} else {
finish()
}
}
You don't need to mess around with the back button behaviour if you're just switching fragments around, and you shouldn't need to pop the backstack either.
The backstack is just a history, like the back button on your browser. You start with some initial state, like an empty container layout. There's no history before this (nothing on the backstack), so if you hit back now, it will back out of the Activity completely.
If you start a fragment transaction where you add a new fragment to that container, you can use addToBackStack to create a new "step" in the history. So it becomes
empty container -> added fragment
and if you hit back it takes a step back (pops the most recent state off the stack)
empty container
if you don't use addToBackStack, the change replaces the current state on the top of the stack
(with addToBackStack)
empty container -> fragmentA -> fragmentB
(without it)
empty container -> fragmentB
so usually you'll skip adding to the backstack when you add your first fragment, since you don't want an earlier step with the empty container - you want to replace that state
empty container
(add mainFragment without adding the transaction to the backstack)
mainFragment
and now when you're at that first state showing mainFragment, the back button will back out of the activity
So addToBackStack makes changes that are added to the history, and you can step back through each change. Skipping it basically alters the last change instead of making a new one. You can think of it like adding to the backstack is going down a level, so when you hit back you go back up to the previous level. Skipping the add keeps you on the same level, and just changes what you're looking at - hitting back still takes you up a level.
So you can use this to organise the "path" the back button takes, by adding new steps to the stack or changing the current one. If you can write out the stack you want, where the back button takes you back a step each time, you can create it!
One last thing - addToBackStack takes a String? argument, which is usually null, but you can pass in a label for the step you're adding. This allows you to pop the backstack all the way back to a certain point in the history, which is like when a browser lets you jump to the previous site in the history, and not just the last page.
So you can add a name for the transaction, like "show subfragment" when you're adding your first subfragment on top of mainFragment, meaning you can use popBackstack with that label to jump straight to the initial mainFragment state, where the next back press exits the activity. This is way more convenient than popping each step off the backstack, and keeping track of how many you need to do - you can just jump back in the history to a defined point
I have three fragments in the MainActivity, i.e Home, Search and More. On backpressed in the More and Search fragments, I want to go to the Home fragment irrespective of the Backstack.
Implement a navigation component and use a global action to move back to the main fragment.
For more info, have a look at Android's latest documentation on Navigation Components
You must implement an intention among the fragments within onBackStack (this if you made the FragmentManager correctly), where whenever pressed, the new intent that will be opened will be from Fragment Home, don't forget to clean the previous intent with
intent.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
You can override onbackpress and navigate to home fragment.
Code for overriding backpress from fragment
val callback: OnBackPressedCallback =
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// Your code here
}
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, callback)
I have a single activity and 4 menu. suppose I click on home menu and add a fragment lets say FragmentA and then from FragmentA I add another fragment say FragmentB now when I press back button it returns back to HomeFragment instead of FragmentA. why is so?
You can do it Using popBackStack(); like
override fun onBackPressed() {
val manager: FragmentManager = supportFragmentManager
if(manager.backStackEntryCount > 0){
manager.popBackStack()
}else{
super.onBackPressed()
}
}
The back button is used to come back to previous Activity only not Fragment.
Current situation:
There is only one activity called MainActivity.
MainActivity maintains the NavHostFragment.
There is a WebViewFragment which embeded a WebView inside.
Thera are many other fragment controlled by NavHostFragment.
What troubles me:
I can forward web pages inside WebView, but when I press back to go back inside the WebView, the NavController handle's it, pop the fragment away.
Since the WebView is inside a fragment not an activity, which means there is not method called onBackPressed() to override.
Reference:
See NavigationBasicSample#github
See Getting start with Navigation#android developer home
As far as I understand, you need a way to handle onBackPressed on your fragment, right? With NavigationComponent you can do it like this, in your onViewCreated:
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (mWebView.canGoBack()) {
mWebView.goBack();
} else {
findNavController().popBackStack(R.id.dest, false)
}
}
})
add a new fragment and inside that place your WebView ,using navigation editor navigate from WebViewFragment to new fragment ,in the right hand side of navigation editor you can see an option to backstack option to manage .
code lab has example https://codelabs.developers.google.com/handling-gesture-back-navigation#5 you need onBackPressedDispatcher which need to be enabled and disabled.
you can use mWeb.goBack(); to goBack to the previous page or for returning back.