Android activity/fragment responsibilities for data loading
When starting a new application for a client, I am asking myself again the same question about who should be responsible for loading data: activities or fragments. I have taken both options for various apps and I was wondering which pattern is best according to you in terms of:
Option 1 - Activity loads data & fragment only displays it
This allows to have fragments that are just fed a bunch of objects to display. They know nothing about loading data and how we load that.
On the other side, the activity loads data using whichever method is required (for instance initially the latest 50 entries and on a search, loads the search result). It then passes it to the fragment which displays it. Method to load the data could be anything (from service, from DB, ... fragments only know about POJOs)
It's kind of a MVC architecture where the activity is the controller and fragments are the view.
Option 2 - Activity arranges fragments & fragments are responsible to fetch the data
In this pattern, fragments are autonomous pieces of application. They know how to load the data they are displaying and how to show it to the user.
Activities are simply a way to arrange fragments on screen and to coordinate transitions between application activities.
Ideally neither Activity
nor Fragment
with UI should contain any "model" logic - these classes should be lightweight and responsible only for UI logic. But when you decide to make a separate model object you have a dilemma to choose where to initialise and store this object and how to deal with configuration changes. And here comes some handy trick:
You can create a model Fragment
without UI , make it retain instance to deal with configuration changes (it's AFAIK the simplest way to save data across config. changes without troubles) and retrieve it anywhere you need via findFragmentById()
. You make all expensive operations inside it once (using background thread, of course), store your data and you're done. For more info, see Adding a fragment without a UI section.
UPD : There's now a better way to deal with configuration changes: ViewModel from Google's Architecture Components. Here's a good example.
In theory you can do whatever you want, if it works. Actually, the fragments and activities display data and deal with their own life cycles.
Since fragments belongs to activity so you have to use both in conjunction to better handle all the data but mostly it depends on your needs.
If you keep in mind the idea that the Fragment should provide the UI and the Activity should provide the processing then you have a good division of concerns and code which should allow the Fragment or the Activity to be reused.
If you know about the MVC - Model View Controller - design pattern then you can think of the Fragment as the View and the Activity as the Model.
Things get much more interesting when you build an application with multiple Fragments.
Some key points as a decide factor -
The idea of a Fragment is that it is a wrapped up chunk of UI that can be used by any Activity that needs it. On this basis you have to ask yourself if the event that has to be handled is the same for every Activity or unique to each Activity. If it is the same then the event handler is better written within the Fragment.
The Fragment doesn't have a UI of its own - it is displayed by an Activity that the Fragment is associated with. The events are generated by objects in the View hierarchy, which is owned by the Activity. If you try to use Android Studio to add an event handler, for example, it will add it to the Activity and not to the Fragment.
You can define the EventListener
that you want to handle the event in the Fragment and then hook it up to the View object in the Activity in which you want to generate the event.
A Fragment is a class that implements the onCreateView
method to supply a View hierarchy that can be displayed by an Activity.
To use a Fragment in an Activity you have to add it using a FragmentManager and a FragmentTransaction. You can add the Fragment using the add method but nothing happens until you call the commit method.
After the method that used the commit, usually the Activity's onCreate, terminates the CreateView event runs the Fragment's onCreateView and the Fragments View hierarchy is added to the Activity's content.
You have to write code to save and restore any additional state the Fragment may have.
If a task is common to all instances of the Fragment then its code should live in the Fragment.
In particular the code to handle events can be defined within the Fragment.
The Activity should be used to host code that processes the data provided by the UI.
Attaching Activity event handlers to the Fragment's UI or is difficult to do correctly.
From scenarios make decision what your app will be. Is it service, activity, widget , even a content provider or a complex system, including some different components. Test your decision against scenarios.
All of these have to work after the Fragment has been destroyed and recreated.
(1) Initialization of the Fragment
, (2) Saving and restoring the Fragment's state
and (3) Implementing something like an event mechanism so the Fragment can get the Activity's attention
The hardest part is implementing something like an event mechanism.
In the case of the complex system, distribute functionalities and data entities among application components. Make a list of components and what they are (activities or smth else).
Make the list of UI components with description what they do (not HOW yet) These will be widgets and activities or fragments or layouts later.
Often you will want one Fragment to communicate with another, for example to change the content based on a user event. All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.
When your app is perfectly modular, fragments don't know about each other. You can add a fragment, remove a fragment, replace a fragment, and they should all work fine, because they are all independent, and the activity has full control over the configuration.
You can't do anything with a Fragment unless you start a transaction. Within the transaction you can set up what you want to happen, usually add the Fragment to the current layout, but nothing happens until you use the commit method.
Efficient handling of data with Screen Orientation -
When screen orientation changes, Android restarts the running Activity ( onDestroy()
is called, followed by onCreate()
).
To properly handle a restart, it is important that your activity restores its previous state through the normal Activity lifecycle, in which Android calls onSaveInstanceState()
before it destroys your activity so that you can save data about the application state. You can then restore the state during onCreate()
or onRestoreInstanceState()
.
However, you might encounter a situation in which restarting your application and restoring significant amounts of data can be costly and create a poor user experience. In such a situation, you have two other options:
1) Retain an object during a configuration change
Allow your activity to restart when a configuration changes, but carry a stateful Object to the new instance of your activity.
2) Handle the configuration change yourself
Prevent the system from restarting your activity during certain configuration changes, but receive a callback when the configurations do change, so that you can manually update your activity as necessary.
What I would do is manage all data flow ( bluetooth, database storage, etc
) in the Activity and use Fragments only for UI display or handling user input.
This way is easier to handle configuration changes/ screen rotations.
Also, if data flow things are heavy to be on UI thread, consider using a Service
with a background thread. If it is a "one shot" thing, you can use an IntentService
, otherwise you can implement a Bind Service
and request a bind from anywhere you have Context.
For more read - fragment-and-activity-working-together.
I prefer and always implemented Option-2 over Option-1.
Reasons for not selecting Option-1:
We should have listeners for events triggered in Fragments and pass it back to activity to load data, process it and push it back to fragment, which makes work more complex.
An Activty can load any number of Fragments, Typically you end up questioning these questions to yourself in a scenario where your app is highly scalable and is already huge . Writing all the events in an activity and passing it over to fragment will be an complex altogether.
As @Ved Prakash mentioned, Handling screen orientation becomes complex if orientation is handled by Activty.
上一篇: 我需要对碎片与活动和观点进行澄清
下一篇: Android活动/片段负责数据加载