I am utilizing a FragmentPagerAdapter to manage a ViewPager with 4 tabs, I'm also utilizing EventBus to monitor changes between tabs. These tabs are all related in the fact that they can add content which should update in another tab.
The way FragmentPagerAdapter works is upon a swipe to another tab, it CAN destroy the view of the previous tab (onDestroyView() seems to be called every single time the Adapter must release memory), however, it often does not destroy the view, it only pauses the fragment.
This being said, I am using an MVP design and I am currently binding the EventBus in onViewCreated() to the Presenter and then unbinding it in onDestroyView(). This allows for events from another tab to reflect instantly in preceding tabs that have been swiped away (so long as the Fragment's views exist still). This removes the necessity to use Sticky events and manage them appropriately.
If the Fragment's views are actually destroyed, when the user navigates back to the Fragment it's onViewCreated() methods will fire redrawing the entire Fragment's views from the most recent data. So both situations are covered efficiently, the situation where a view still exists (and it gets updated), as well as the situation where there is no view, and a new view must be drawn.
Therefore, I don't see any holes in my plan, however, I have NEVER seen this approach discussed. Is there a really bad reason I should not be doing this? Or is this just a good solution for a very specific design?
Your expertise is appreciated!
I have done similar things before. It's common practice to use an event bus along with the lifecycle of views in order to best manage their display when it's relevant to do so. The problem is registering a listener before the view is actually available, and unregistering after it's no longer going to be used, which is sounds like you are not doing.
BTW, for anyone reading this, there are different practices for different situations. For Activity instances it is common to use onStart and onStop to register and unregister the listener, but you still have to understand the flow of events through your bus to see if it still makes sense.
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.
As the title suggests, I want to retain my fragments. I have enforced my app orientation to always be in landscape mode in the manifest file so that there will be no rotations.
I have read:
Understanding Fragment's setRetainInstance(boolean)
and
Why use Fragment#setRetainInstance(boolean)?
However, I am not sure if they apply to my situation.
My project consists of a ViewPager with swipe tabs. How can I ensure that the fragments used in the ViewPager are the same ones as created when the MainActivity first starts? Would I use the same tagging method and findfragment by tag?
Additionally, where would it be best to check for the tagged fragment, else create a new fragment?
Just a side question related to ViewPager: what can I do to immediately create all fragments used in the ViewPager when the mainactivity is started, rather than to wait for a swipe event to occur?
To answer your last question view pager will by default create the fragments around the current fragment so you don't need to worry about that part. What I would recommend is let the view pager manage your fragments for you rather changing the behaviour since you might face performance issues.
SetRetainInstance simply keeps the instance of your fragment when its detached so it's up to you to assess whether you need to use it or not.. is there anything you want to maintain about that fragment? if not then do not use it, free your memory as much as possible.
For the last question, why do you want the same fragments created from the first time to be retained ? all the time? if you NEED to do that then rethink your structuring. gracefully recreate your fragments and maybe have some caching of your data on another layer if that is what you are worried about.
I have implemented ViewPager and number of Fragment as child, here every child override own onAttach, onCreateView, onViewCreated and setUserVisibleHint.
In my app navigation behaviour is random, it not be in sequence every time. Since page viewer perform caching to load extra child, and this is what my problem is. I am not sure exactly when I should initialise/release member of child class.
Required suggestion from you guys, will it be preferable to use PageViwer in this case or I should go with traditional activity flow for each of component.
ViewPager is typically used for move efficient horizontal item to item navigation. Typical use cases would be
Swiping through the related items (e.g. emails, images, songs of an album, etc.)
Swiping between the tabs
Swiping back-and-forth in a wizard-like activity
For more details you can read a section about Swipe Views Android Design pattern.
Regarding the lifecycle, it basically uses the same lifecycle as any other Fragment. The only difference is, that lifecycle methods can be called a bit later or earlier than you expect, because of fragment's caching ViewPager implements.
I am not sure exactly when I should initialise/release member of child class.
You should basically rely on two methods: onStart() and onStop(). In onStart() you create class members and initialize everything you want to. In onStop() method you should deinitialize everything and remove all listeners you set in onStart().
Method setUserVisibleHint() is used independently of onStart() or onStop(). You shoud better not initialize or destroy anything in there. You must not consider it to the a lifecycle method, because it's not. It's there just to give you a hint, that your fragment is visible to the user. Here you can start or stop animation, or request data update or perform similar tasks. This is the only purpose of this method.
Required suggestion from you guys, will it be preferable to use
PageViwer in this case or I should go with traditional activity flow
for each of component.
If your activity fits into one of the points mentioned about, I would suggest you to use ViewPager. Otherwise you might consider other options.
Update: Most likely you won't override onCreate() and onDestroy() lifecycle methods of a fragment very often. You will use onCreateView() and onDestroyView() methods instead. There you can implement so called static initialization, the initialization which doesn't change while a fragment is still alive. This is layout initialization and similar tasks.
ViewPager Usages
Screen slides are transitions between one entire screen to another and are common with UIs like setup wizards or slideshows.
If you have good knowledge in Fragment than ViewPager is right component for implements.
Because viewpager provide a place which you can add fragment runtime.
For eg.
If you want to use TabBar in your project than viewpager is right component for using. Because it's provide a place which you can add Fragment runtime. Tabbar is common in android application. It's provide lot of functionality inbuild we can use to add fragment runtime.
Facebook app using ViewPager to manage tab. Viewpager provide smoothness of your application.
You can Download example from this url and check your requirement fulfill or not
You can download the Example here
ViewPager
It is an widget
Allows the user to swipe left or right to see an entirely new screen.
Easy to show the user multiple tabs
Dynamically add and remove pages (or tabs) at anytime.
To Read More: http://architects.dzone.com/articles/android-tutorial-using
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.
I know there have been quite a few questions about this, however, I'm still struggling to understand what role the Activity class should play when implementing the traditional Model-View-Controller design pattern on Android?
My gut feel is that it should be the Controller, however that means a one-to-one relationship between UI screens (since you must have one Activity per screen) and controllers, which defeats the point of MVC's loose coupling between the different components.
You are right. The xml interfaces could be defined as the View and your other class working with data as the Model.
The activity receive all the events and user inputs from the View ,so, we can easily said that it is the Controller.
But let's be clear , it's not a perfect (does it really exist ?) MVC
Have a look to this question , and more specifically , the first comment of the accepted answer, it may be useful
Activities can make competent controllers and, with fragments, you can also implement hierarchical MVC. Most of making MVC work is up to the programmer, because even in the strictest frameworks you can still find ways to do crazy things.
Android does not have a good architecture and it does not follow the MVC design pattern.
The best way to conceptualize Activity in MVC is as a View (with some controller logic) because it gets destroyed every time that a configuration change happens, such as a screen rotation or locale change, losing all its state.
The controller in this case would be the Application object, because it is your bridge to access the view (Activity and its GUI components) from code outside the Activity context. You have to use singletons so that there is only one Application object at a given time, otherwise there will be one Application object per process.
The Application object is not a good place to store the Model because its life cycle is detached from that of the Activities. It can get destroyed and recreated at any point of an Activity's life cycle (while the application is in the background) without causing it to restart, and then all its variables and references not assigned inside its onCreate() method will become null.
The Model therefore has to be stored on a GUI-less, headless fragment with setRetainInstance(true), that is linked to an activity, and has to be re-attached to it every time the activity is recreated. You have to use a fragment manager to ensure you are recovering the retained fragment and not creating it anew. This is also the best place to run background tasks, though you can also run them in the Application object. Never run tasks on an Activity as they will get destroyed on configuration changes.
I think the confusion may come in with defining a view as XML and so the Activity is mistaken for being the view. It's not. You pass the view (your XML layout) into the Activity which will then inflate the views contained within the XML layout. Your activity also passes data (models) into your views (EditText, TextView, extended version of base views, etc).
If you really want MVC then you can achieve this simply by setting up your view in an XML layout, create a view object which extends from your root view (if it's a RelativeLayout extend from that). From there you add your accessor methods and different logic needed for that view and you can then add unit testing around that.
In the Activity you will no longer pass in the ID of the layout and will instead do something like this:
CustomView customView = new CustomView(...);
setContentView(customView);
...
Of course almost all apps won't do this and you really don't need to do this. Calling findViewById is enough to link to that view object and call on the methods it has. Which in my mind, is MVC.