The Scene
I have an activity that houses 2 fragments .
Activity A is launched.
Fragment B completely takes over the activity A (UI wise).
Here depending on the operation , Fragment C launches and takes over the whole UI
The Target
I want to be able to know when a user presses back from Fragment C , and lands back on fragment B .
The Problem.
We all know that we CANNOT use the onResume override in the Fragment B , because this onResume is closely coupled with the Activity's lifecycle. If there was an override like onResume in Fragment B , it would have really helped my case. I know that the Fragment B is not onPaused when Fragment C overtakes it , so I am aware that onResume like strategy wont work .
The Solution
I think I can attach a callback onBackPressed in Activity A . Something like .
Psuedo Code
private onBackPressed()
{
if (currentFragment == Fragment C) {
FragmentB = findFragmentB();
//call custom method written in FragmentB
FragmentB.onBackPressed();
} else {
super.onBackPressed();
}
}
Before I proceeded , is this the right direction to move in ?
Exactly,,, if there is most suitable and easy solution for this problem. i think you should continue with this. I find out other ways but this was better and easy then others
Something alone the lines of this should work
BaseFragment currFrag = (BaseFragment) manager.findFragmentById(R.id.fragmentname);
currFrag.onFragmentResume();
Not much to explain here, onFragmentResume literally calls onResume of the fragment.
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 have a Fragment A in My app.
From the Fragment A, I am moving to Fragment B.
Note that I am adding the Fragment B on Fragment A (not replacing the Fragment.)
Now, When I coming back to Fragment A from Fragment B, I have to call a method of Fragment A and that's Why I am calling that method in life cycle method of Fragment A : in onResume(), onViewCreated()
But What I noticed by putting log in both the method that these methods are not calling means I am not getting Log in logcat and the method which I have called in these two methods is not executing.
What might be the issue? Thanks.
I am doing as below for your reference:
override fun onResume() {
super.onResume()
Log.e("onResume 1","onResume 1")
(activity as HomeActivity).updateToolbar(false)
setLanguageSpecificData()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.e("onViewCreated","onViewCreated")
setLanguageSpecificData()
}
Problem:
The way you mentioned in your question that:
I am adding the Fragment B on Fragment A (not replacing the Fragment.)
So, There is a difference between what lifecycle methods gets called based on replace & add.
If you take a look at this answer :https://stackoverflow.com/a/21684520/9715339
In terms of fragment's life cycle events onPause, onResume,
onCreateView and other life cycle events will be invoked in case of
replace but they wont be invoked in case of add
Also, It's tied to activity lifecycle as well.
Solution:
Looking at your code you want to update something when current visible fragment changes or in other words backstack changes.
For that you can do this in your activity:
supportFragmentManager.addOnBackStackChangedListener {
//when backstack changes get the current fragment & do something with that info
val frg = supportFragmentManager.findFragmentById(R.id.root_container)
if (frg is AFragment){
// do something like updateToolbar(false)
} else if (frg is BFragment){
//something else
}
Log.d("FrgTest-",frg.toString())
}
In fragment you can do requireActivity().supportFragmentManager & rest will be fine.
Read:
This is just an example for backstack change. If you want to communicate between fragments you can use other ways like setFragmentResultListener as well.
This may help: https://developer.android.com/guide/fragments/communicate#kotlin
I've a fragment A. I add() it with tag like this:
fragmentTransaction.addToBackStack(special_tag);
Then I simply add() fragment B on top of fragment A. After that, I decide to remove fragment B and go back to fragment A using:
activity.fragmentManager.popBackStackImmediate(special_tag, 0)
When I reach the fragment A, it seems that fragment doesn't re-run it's lifecycle methods: onAttach(), onResume(), onCreate() ect.
Can someone explain this behavior and maybe suggest an alternative?
(I need to "refresh" the data when I come back to fragment A second time)
What is causing this result?
Is there a clean solution/work-around?
Update
Fragment B is GuidedStepFragment and does not have a .replace() function. I found that it has finishGuidedStepFragments(), but it behaves the same (it does not call fragment life cycle functions)
Situation (again):
Fragment A (Simple fragment) -> .add(Fragment B) (GuidedStepFragment) -> popBackStackImmediate() or finishGuidedStepFragments()
I add Fragment B like this:
GuidedStepFragment.add(activity.fragmentManager, fragmentB.createInstance())
Using fragmentTransaction.add(Fragment) doesn't remove Fragment A. What is actually happening is that Fragment A is still running behind Fragment B. Since Fragment A never stopped running, it's lifecycle has no need to retrigger.
Consider using fragmentTransaction.replace(Fragment) and replace the fragment in the container (fragment A) with fragment B. If you pop that transaction from the back stack, then Fragment A will reattach and follow your expected lifecycle.
Update
Since you seem to be using GuidedStepFragments from the leanback library, this is a little tricky. GuidedStepFragment actually performs replace(...) under the hood, but you're adding fragment B to a different container so the original behavior I mentioned doesn't apply.
I'm not super familiar with leanback (since it's usually only used for android tv), but I do know that you can at least do the following. If you keep track of your backstack size, when all of the GuidedStepFragments have been popped, you will have returned to your original fragment. For example, let's assume your backstack starts at zero:
activity.fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (activity.fragmentManager.getBackStackEntryCount() == 0){
// handle your updates
}
}
});
// the next line of code will add an entry to the backstack
GuidedStepFragment.add(activity.fragmentManager, fragmentB.createInstance());
// eventually when back is pressed and the guided fragment is removed, the backstack listener should trigger
I'm so very confused and have been reading on this topic for a while.
I have a MainActivity that has multiple possible contents (switched between via navigation drawer), which I've set via multiple fragments (lets call them Fragment1, Fragment2 and Fragment3).
That works fine.
One of my fragments, Fragment3, is a View that can segue to a new activity, View2.
View2 has a back button. When I press on the View2 back button I want to see Fragment3 on my MainActivity, not Fragment1, which is what I currently get. This is because OnCreate, by default, loads Fragment1.
What is the best way to do this?
Thanks so much in advance! (vent: iOS makes this so much easier).
The official documentation for Fragments states that you should make sure to call addToBackStack() before commiting your fragment transaction on your first activity holding the 3 fragments.
In order to go back to the last used fragment from the second activity , you should override the onBackPressed() method in this activity :
#Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
The documentation is very complete on the subject : Read it here
Update:
I just added this to the back button code:
finish();
return true;
I had to do it within onOptionsItemSelected(MenuItem item)... for some reason onBackPressed is not fired.
What I am attempting is to wait in my main activity until my fragment finishes, so I can execute code without causing problems in the fragment. I have tried many methods and can't get a solution. Heres some of my code from my main activity:
if (null == savedInstanceState) {
getFragmentManager().beginTransaction()
.replace(R.id.container, CameraFragment.newInstance())
.commit();
}
This will run a fragment that takes a picture and saves it.
The problem i'm having is, for example, I want to wait until this fragment has finished, then execute more code from my main activity. I can't find a working solution.
Edit: Solved, see the answer. Thanks!
Create a method on your activity, to run when your fragment is complete
Implement the OnResume method on the fragment like this:
#Override
public void onResume() {
super.onResume();
((NameOfActivity) getActivity()).afterFragmentComplete();
}
You're confused. You don't run a fragment. You display it. There is no way of "waiting for a fragment to complete" because fragments don't have the concept of completion. If you have a fragment that does something then wants to notify the activity to do something (which may include getting rid of that fragment) the way to do it is to pass the fragment an callback to the Activity that it will call when needed (such as when the user presses a save button).