I need to know when fragments(and which fragments) are added/removed/replaced, especially when popped from backstack. I'd like to be notified both before and after the transactions occur, as I sometimes want to delay a transaction for changing an underlaying layout. So in general, I'd like to run some code before and after the transaction plus eventually delay the transaction. I've already thought about using custom animations for that purpose but transactions only accept ids, no objects/classes. And there might be a better solution I currently can't think of. Any ideas?
I've been using the fragments for quite a while and if you want something ready out-of-the-box you're out of luck.
The only listener available is the addOnBackStackChangedListener and that's it.
But remember that every call that creates and commits a fragment transaction is made by you, either directly via code or indirectly via fragments instantiated on a XML layout or passed to you via the Actionbar tab.
So based on that you should be able to organize your code in some way to always call through a wrapper, but it will be a big work for sure.
Related
The idea of using MVVM is that view observes ViewModelchanges and acts. I'm using an Activity which uses 7 Fragments and the navigation between them goes through observing individual changes in the Activity from different Fragments and launching/replacing Fragments accordingly. For instance,Fragment L calls setValue, then as a result the main Activity receives the event and switches to Fragment M and Fragment M calls getValue from the observed MutableLiveData and not directly functioning as a listener to changes. Does that the right structure or should each Fragment observe changes by himself ? What would the right way to handle multiple navigations between multiple Fragments
I don't see anything wrong in what you just said. Fragments should be independent from each other unless they are nested.
If you need communication between fragments that can be done in many ways. The most basic way is to do that through activity. Activity knows how its fragments interact with each other, but fragments remain independent. They can listen to events, no problem here, but make sure you have a 'rule' in your project about how you handle events.
E.g. I prefer having one listener at a time to have the order more predictable. If I want multiple fragments to handle the event, I usually place the handler in the activity and then pass the event to fragments in the exact order I need. Otherwise it might quickly get out of control.
There are other ways too, such as EventBus, BroadcastReceivers or any other event-based mechanism.
I hope that helps. If I didn't answer your question then to answer it more precisely I'd need the question to be more specific.
After spending a fair bit of time figuring out that the reason my fragments chosen from a drawer layout weren`t displaying sometimes due to the choreographer skipping frames (I was using transaction.replace rather than show/hide) it made me wonder -- what are the situations where one would want to use replace rather than show/hide or detach/reattach? My problem went away when I switched to using show/hide btw.
Taken from this thread I got this on what happens when you call FragmentTransaction.replace():
Android will effectively perform a sequence of
FragmentTransaction.remove(...) (for all Fragments currently added to
that container) and FragmentTransaction.add(...) (for your supplied
Fragment). Removing a Fragment from the FragmentManager will cause the
Fragment to be destroyed and its state will no longer be managed. Most
noticeably, when you re-add the Fragment all of the views will have
been reset. Note: since you are reusing the same Fragment instance,
the Fragment will still keep the value any instance variables.
and from this thread I got that it is probably better to show/hide rather than replace if you plan on using that fragment again. My question is, in which situations do you use FragmentTransaction.Replace()? The only place I could see it really being useful is for something you know you won`t need again, kind of like a dialog picker with options but I use dialog fragments for those situations.
Does anyone use FragmentTransaction.replace regularly, and if so, why did you choose that over another method? Cheers
It maybe useful, for example, when implementing a deep fragments hierarchy in Multi-pane pattern (when click on item in the right fragment moves it to the position of the left).
Also, since hiding a Fragment keeps it in FragmentManager, it maybe expensive if you have a heavy content in it or hide multiple instances. Calling remove() or replace() and properly saving fragment's state is more Android-way, I think.
In my Android project I have an Activity that uses a Master-Detail view, created with two fragments.
My detailfragment is giving me some "problems" though.
It consists of 50+ controls (TextViews, EditTexts, CheckBoxes, Spinner). Of this 50+ controls I programmatically get a reference to 32 of these controls in my detail-fragment and load their data from my SQLite database.
When I run this and initialize my controls by using
(SomeControl).findViewById(R.id.mycontrol);
LogCat keeps warning me about that I might be doing too much on the main thread.
I know that findViewById and inflating views is an expensive operation, so I had an idea!
I was wondering if there was some way to use the viewholder pattern or view-recycling on my detail-fragment like I'm doing on my ListFragment. that way I could avoid reinitializing my detailview each time I select another item in my ListView. And avoid calling .findViewById as much as I do. Does anyone have an idea on how to implement something like this. Would it make any difference if I did initialization of the controls in the onCreate-method of my detailsfragment? I was also thinking about making my detailsfragment a "singleton" and then just use getLoaderManager().restartLoader when the selection of my listfragment changes. Any thoughts on all of this would be very much appreciated.
Well unless you're using the exact same layout for each control then I'm not sure if there's a way to do that.
But there may be a way to solve your problem: using an AsyncTask.
As long as those controls aren't necessary for your program to crunch data (and from your explanation I don't think the UI elements would be triggered until the user has interacted with it) you should be fine and the main thread will be free to do whatever it needs. The only downside I see with this method would be that some UI elements might appear maybe a half a second late (not so bad if you think about it).
Found a solution. Had to change my implementation entirely though.
Now my implementation is using loaders on both ListFragment and DetailFragment.
Here's a list of changes I've made:
Created a interface for my ListFragment with one method (onSomethingClicked(SomeObject obj)) and made ListFragment observable through this interface.
Implemented the interface in my DetailFragment and registered a listener on the ListFragment.
Implemented the method onSomethingClicked() in DetailFragment. When this is triggered i pass data from ListFragment to DetailFragment and restart my DetailFragment-loader and load data into my already initialized controls in OnLoadFinished.
No need to inflate the view every time the selection in the list changes and no need to .findViewById's AND MOST IMPORTANTLY no more Choreographer warnings :)
Is there any way to do this?
I'm working on an application that uses multiple tabs to manage bluetooth connections, messages and other stuff.
I need my activity to inform each of these tabs (fragments) of certain events such as connection status, messages delivered.
I used an approach where i keep a reference to each of my fragments in the adapter. The problem is that fragments are not instantiated until o switch to the tab that uses it.
Is it possible to instantiate all four fragments so that i can update their view even though it has not been shown yet?
Thanks a lot,
and sorry for my english
If you use a ViewPager (you mentioned "tabs") just call setOffscreenPageLimit() in onCreate() of your App (after initializing ViewPager). Set the limit to the number of your fragments. With this all of your fragments will be instantiate.
I would suggest using frames, and then populating each one with a fragment when the time is right. When you get to the correct tab, do a null check to see if the frame is actually a part of the layout. If it is present
then place the fragment in the frame. That should do it.
I've started developing Android apps and I am wondering which way is better in case of adding fragments to activity. Let's assume that view for activity contain always three fragments. They won't changed. Always be the same. Thus is it better to add them by tags or include them in the activity code?
And a second question issue:
Let's say I have activity with fragment which is a list. Then when I clicked on item I want to show new view. Can I then replace the list fragment with new completely different fragment? Even if the answer is yes then is it better than creating new activity?
Thanks for all replies
which way is better in case of adding fragments to activity
One approach is not necessarily 'better' than the other - they both serve their own purposes, as with any static vs. dynamic comparison.
For example, fragments declared in a layout cannot be given arguments using setArguments(). Such a fragment can also not be replaced by another fragment: if it's part of the layout, it'll always be there. Of course you can still show/hide the instance, but attempting to actually remove it through a FragmentTransaction will simply not work. Static elements are usually easier to work with though, because they have a well-defined lifetime and behaviour.
Regarding your second question: yes, that's very possible. Some developers build their app around a single Activity container, swapping out fragments as the user navigates its way through the content. In most cases, from a user's point of view, there is little difference between doing this or having multiple activities. The important thing to keep in mind is to choose an approach you're comfortable with, doesn't overly complicate things and takes advantage of the patterns explained in Implementing Effective Navigation.