framentA calls fragmentB via an mother activity. FragmentA is no longer in memory. FragmentB calls fragmentA(go back to previous screen). FragmentB has some data to share with FragmentA. But, how?
here is what I tried:
static variable - it worked, but a bad habit, I can not use it
viewModel - each fragment creates it's OWN instance of view model. Therefore the 2 instances of the viewModel will not work.
DB - not a good pattern. Therefore I cant use it.
I think what you need is to store the fragments in Fragment Manager, when you do that you are basically trying to maintain a back stack of your fragments:
FragmentManager fragmentManager = getSupportFragmentManager();
//or FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.add(FragmentToBeAdded, "textRelatedtoFragment")
.addToBackStack(null)
.commit();
Adding to the backstack helps in saving the state of the fragment.
My suggestion would be:
For Fragment Navigation use: https://developer.android.com/guide/navigation/navigation-getting-started
It will greatly simplify your in-app navigation.
For passing parameters between Fragments/Activities:
First solution is to use ViewModel with scoping of Activity using by activityViewModels(). Read More here: https://developer.android.com/jetpack/guide This will give you an indirect way of passing arguments.
Use SafeArgs (part of Navigation component) to directly pass needed data.
More information can be found here: https://developer.android.com/guide/navigation/navigation-getting-started#ensure_type-safety_by_using_safe_args
Related
I have 2 fragments. My first fragment have button which leads me to second fragment. It has this code:
binding.btnGet5Days.setOnClickListener {
val forecastFragment = ForecastFrag()
val transaction: FragmentTransaction =
parentFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, forecastFragment)
transaction.addToBackStack(null)
transaction.commit()
}
In my MainActivity i have this code:
val cityFragment = CityFrag()
val fm: FragmentManager = supportFragmentManager
fm.beginTransaction()
.add(R.id.fragment_container, cityFragment)
.commit()
Fragments are in FragmentContainer,
The problem is when i'm joining second fragment through this button and turn my phone into landscape mode, my first fragment layering to my second fragment. How can i solve it? :)
It's hard to know without seeing your full code, but it's possible the code you posted from MainActivity is adding a fragment on top of the existing stack. When you rotate the device, the Activity is destroyed and recreated, but the FragmentManager maintains its state so you don't lose everything. If your recreated activity code always adds a new fragment instance, you'll end up with what was already there, plus another CityFrag on top
The official recommendation is to use the Jetpack Navigation library, which will handle all that for you. If you don't want to go that far right now, you'll have to do your own checking and creation logic.
One thing you can do is to check if the savedInstanceState Bundle passed into your activity's onCreate is null - if it is, then this is a fresh start, and you can initialise with your first fragment. If it's not null, then your app is being recreated from some saved state, so you should probably let the FragmentManager take care of restoring itself and its back stack.
Otherwise take a look at FragmentManager - there's a bunch of useful methods like getBackStackEntryCount, findFragmentByTag etc. that you can use to work out what state your fragments are in, and if you need to add one or not. Depends on your code!
That is what I have in my app
Activity with 2 fragment with ViewModels and Databinding.
Room Database with Livedata to update UI continuously.
Navigation Controller to navigate between fragments.
Fragment #1 have RecyclerView (List of Custom Object).
Fragment #2 is to Insert or Update operations (Transactions).
Everything works fine as expected, but one thing I can't figure out why it happens.
When I go to Fragment #2 to Insert or Update data to Room Database then back to Fragment #1 with (top or bottom) back button, fragment #1 doesn't reload and data doesn't change (update) until I reload data.
In other case when I Insert or Update data at the same fragment the list changes immediately.
Do I have to make insert and update operations at the same fragment?
Can't I do it at other fragments and when I go back to the list fragment I find that data is been updated?
Keep in mind that it was work like I hope but at some point i really don't know it doesn't any more !!
After searching, the problem was that I was create instance from repository which contain ROOM database DAO, So all LIVEDATA connections to the database was removed
The solution was to use singleton pattern, which mean to use only one repository instance and one room database instance during the full lifecycle of the activity which contain my fragments.
You can do this many ways, I recommend you to use Dependences Injection
Tool I used was HILT DAGGER here here
Create a function in class where fragments are defined like this.
public void refresh( ) {
fragment = new ListFragment();
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
if (fragment != null) {
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.container, fragment).commit();
}
}
Now Call that in your 2nd fragment where you want to call 1st fragment after any action.
((MainActivity) Objects.requireNonNull(getActivity())).refresh();
In my activity I use three buttons at bottom to choose between fragments like this for example:
scenarioFragment = new ScenarioFragment();
android.app.FragmentManager fragmentManager = this.getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment, scenarioFragment, scenarioFragment.toString());
fragmentTransaction.addToBackStack("stack");
fragmentTransaction.commit();
so in ScenarioFragment, I bounded a connection to my service.and whenever I change between fragments a new fragment is created and I have to bind a new connection.
I want to save all fragments state and restore it as they choose.
thanks.
According to what you said, your Fragment have the same Activity as a parent.
Assuming this, you could create a ViewModel (Component introduced as part of the Android Architecture Components) for your activity and put whichever state you want in them.
Then, inside each of your Fragments you can get the ViewModel with the statement:
ViewModelProviders.of(getActivity()).get(ViewModelClassName.class);
The key to this statement is to make sure you pass in the getActivity so that you can get the same ViewModel instance in all the Fragments as long as they are attached to the same parent. If you pass the Fragment instead of the Activity like this ViewModelProviders.of(this).get(ViewModelClassName.class); you will have a new instance of the ViewModel tied to the scope of the Fragment that will be cleared if the Fragment is destroyed.
This is possible because the ViewModel class will be created using the scope of the Activity and it doesn't matter how many time you recreate your fragment you will be getting the same ViewModel instance with your state.
You can learn more about Android Architecture components here.
If you wish to understand a bit more about how the ViewModel works internally you can find out more on a post I wrote here.
I'm learning about fragments I have some doubts. Consider following code:
FragmentManager fm = getFragmentManager();
Fragment MyFragment = new Fragment();
fm.beginTransaction().replace(R.id.my_container, MyFragment).addToBackStack(null).commit();
My question is:
what exactly does replace do?
What happens if I create many fragments this way (to replace previous ones in a container).
Can it in any way be bad for memory usage?
Is it considerably better just to change fragment's content?
Replace removes all the fragments that are in the container and adds the new fragment to the container. (if there isn't a fragment in the container then it just adds the new one).
If you create many fragments this way then every transaction is saved to the backstack so you can reverse the transaction by pressing the back button.
The only thing you can do is to create a variable fragmentTransaction and use the fm.beginTransaction() only once and not every time you want to replace the fragment in the container.
I don't think so, fragments should be modular and reusable.
You can read more here:
https://developer.android.com/guide/components/fragments.html
it simple put another "layer" on container.
appcrash
yes
No, fragment is the easiest way.
Using fragment & backstack tag to reference to a Fragment if you want to call fragment again and process Back button.
fm.beginTransaction().replace(R.id.my_container, MyFragment, "FRAGMENT_TAG").addToBackStack("FRAGMENT_BACKSTACK_TAG").commit();
I created a navigation drawer. Now,navigation drawer requires all fragments. I want to send some information and move to this fragment which contains drawer from an activity. How do I implement this ? I am using Intent(activityclass.this,fragment.class) for navigation and putExtra for sending data. But the app crashes.
Fragments are not loaded using Intent. You need to use FragmentManager:
Fragment fragment = new MyFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.container,fragment).commit();
your approach needs some modification i would like to refer the below links for better ways
official tutorial
Some good practises for your app communication