I'm wondering if it is better to have a Module per Activity than a Module per Fragment? In one of my projects, I have an architecture to have a Module per Fragment because I use Activity just to hold and swap Fragments and nothing more. I only create Presenters and Interactors when I need them, i.e. when Fragment.onCreate() is being called.
But I can see guys are creating Module per Activity in their examples. While the idea to have an independent Module for Activity sounds perfectly reasonable as for me from a modularity perspective, but I still believe creating and keeping all objects (Presenters, Interactors) before you actually need them is not a best idea. You can't also release resources when you don't need them, which you could easily do for Module per Fragment when you just release a scoped graph in Fragment.onDestroy() event.
The examples assume you're working with several activities, each with their own clear purpose and scope. There exists a scope A for the application wide dependencies, and scopes B, C and D for each of the Activity dependencies.
You're basically adding an extra layer to the hierarchy: Application-Activity-Fragment. In that case, since you're working with a single Activity, scope A is roughly the scope for the application and activity dependencies, and B, C and D become Fragment scopes.
So yes, it makes sense to create a module for each Fragment.
Related
Scenario 1 - If we use ViewModels to communicate between fragments, then the ViewModel has to be created by activity reference and hence going to stay there in memory until the activity is destroyed.
Scenario 2 - In master-detail flow ViewModel makes our life easier but again the memory usage issue is there.
Scenario 3 - We have viewModelScope in the new version of arch library to cancel jobs with Fragment/Activity lifecycles, but if ViewModel is created with activity reference then it's going to stay there until activity is destroyed. Hence the job can still be executing and fragment is already gone.
You can use ViewModels to communication between two different fragments(aka SharedViewmodels) because it's simple but it's not perfect.
As you know the SharedViewModels must be alive until the first joint parent (activity or fragment) is alive.
but wait ...
What is the purpose of ViewModels?
Are we create ViewModels just for communication between fragments? Absolutely not.
Is the use of ViewModels against the purpose of ViewModels? no, I say it's not perfect use them for communication between fragments but if you have a small project you can use them because it's simple.
So what can I do instead of using ViewModels for communication between fragments? You can build independent UI components and use them for communication between fragments.
What is the advantage of building this weird independent UI components? In this way, each component has its own ViewModel (or Presenter) and they haven't any parent/child relation; Instead, they updated from the same business logic or in reactive programming they are just observing the same Model.
What is the meaning of building independent UI components and how to build them? if you are already familiar with reactive programming, I recommend reading this amazing blog post by Hannes Dorfmann; If you don't, I simply propose using EventBus library for communication between fragments but You will soon realize that too much usage of this library leads to spaghetti code.
Scenarios
If the fragments are not part of a flow/group, then don't share the ViewModel, just pass some id/data to the new fragment, create its own viewmodel, and query the data for the fragment from its own viewmodel.
If the fragments are part of some flow/group (cart/checkout/booking flow, multi-screen registration process, viewpager fragments, etc) and the logic is common enough, then share the viewmodels between the fragments. In single-activity architecture, I put these flow/process in its own root parent fragment that acts as a host and is used to create the scope of the viewmodel. For example:
MainActivity ->
-> RootAuthFragment
-> SplashFragment (replace with below)
-> LoginFragment (add to backstack with below or onsuccess login go to MainFragment)
-> SignupFragment (onsuccess go to Main)
-> MainFragment (replace with RootAuthFragment)
In the above scenario, you can share the viewmodel between login and signup screens with RootAuthFragment's scope. If you have a multi-screen signup process, then you could move that into separate root fragment and create a separate viewmodel for the signup flow.
Bundle vs ViewModels:
Bundles are used to pass some values. So, use it just for that. I use bundles to usually pass primitive data types or enums and based on that I query the actual data from the viewmodel (through android room or retrofit) or if the data objects are small enough, I make them parcelable and just pass that.
If you have a shared ViewModel and it's becoming a god class and does a lot of different things, then it means those fragments need separate ViewModels. Don't share the ViewModel just for data. Share the ViewModel for the common/shared behaviour/data/logic (whichever makes sense for your particular use cases)
I prefer you should use View Models approach if you are using single activity architecture. To justify my answer I will clear your scenarios here.
Scenario 1 - If we use ViewModels to communicate between fragments, then the ViewModel has to be created by activity reference and hence going to stay there in memory until the activity is destroyed.
Scenario 2 - In master-detail flow ViewModel makes our life easier but again the memory usage issue is there.
As for memory you are already holding information into memory there is no escaping there. If you don't need data for stay there then you can clear data from models also but again it will kill the purpose of storing data in the first place.
If you pass data using bundle it's also going to take memory there also.
Scenario 3 - We have viewModelScope in the new version of arch library to cancel jobs with Fragment/Activity lifecycles, but if ViewModel is created with activity reference then it's going to stay there until activity is destroyed. Hence the job can still be executing and fragment is already gone.
That's the main purpose of using view models it will store the last state for user where he left.
As per https://developer.android.com/topic/libraries/architecture/viewmodel states
This approach offers the following benefits:
The activity does not need to do anything, or know anything about this communication.
Fragments don't need to know about each other besides the SharedViewModel contract. If one of the fragments disappears, the other one keeps working as usual.
Each fragment has its own lifecycle, and is not affected by the lifecycle of the other one. If one fragment replaces the other one, the UI continues to work without any problems.
I'm trying to use MVP in my new project. I have a Single Activity and multiple presenters that can be associated with it.
Presenter1 - Load Activity Data
Presenter2 - Load User data - that can be used in multiple Activities (So this presenter will be used in multiple activities
Presenter3 - User Actions - This can also be used in more than one Activities.
For now, I have used all the 3 presenters for one Activity. Is there anything I can do to use only single presenter to access all the methods for the 3 presenters? Searched a lot, but could not find any relevant reference. Thanks
I'm not sure it is the answer you're looking for but you could try an architecture more like clean architecture and isolate the logic of each of your use cases in an interactor and then inject your three interactors in one unic presenter for your activity.
And later, when you'll need to re-use that logic you will have a LoadUserInteractor and a UserActionInteractor to inject into that new presenter.
If you do not want to create interactors in your architecture you could create an abstract present who have the methods for load user data and user actions and let your activity presenter extends it with the load activity data but I'm not sure it will be long before it cause you some maintenance problems.
I'm using dagger 2 for dependency injection in my android app project.
and the question is how to remove references from component when the activity dies ?
I've read some documents about custom scopes and i've created a custom scope called #ForActivity, so references that have this annotation on them will remove when activity dies, but they don't.
any suggestions on this problem ?
If your component shares the lifecycle of the Activity—that means create the component in onCreate, store it in the Activity itself—it will be garbage collected along with the Activity at the end of the Activities lifetime.
If on the other hand you put a component that references the Activity in some way in a static variable, or some other longer lived object, you will create a memory leak. This is the only thing to keep in mind.
Nothing will be magically "removed" since Dagger just generates POJOs that handle object creation for you. Usually it is enough to just let the GC do its job.
Scopes just group dependencies and define relationships, but in the end your component is just an object that holds more objects. The Garbage Collector will remove it along with the Activity and everything else if you don't create memory leaks as mentioned above.
I recently also gave 2 detailed answers about scopes / activities / scoped objects, where you find more concrete examples on how to work with scopes / activites:
Dagger 2 Scopes, where to place Presenters?
Dagger 2 with MVP, avoid creating extra presenter object on view recreation
I have been researching this for about an hour and cannot figure out whether to use fragments within an activity or start a new fragment activity.
Some sites make it sound as if you should have 1 activity and EVERYTHING else is a fragment. Is that the more proper way now? I can't figure out when you use an Activity (or fragment activity) and when you use a fragment.
I have an app for a conference with:
-Speakers (and sub views/activities/fragments) for each speaker.
-Schedule (different sections for each day)
-General info
-Sessions (different sections for each session).
So do I have 4 activities each with their own fragments or do I just use 1 activity with fragments and nested fragments?
You could do it either way, but generally it is best to use an Activity (or FragmentActivity) for each "screen".
If the user sees your app as logically a single screen that has little panels appearing/disappearing for different kinds of data, then use one activity with a lot of fragments. If the user sees it as "going to different screens", then you probably want multiple activities.
If you go with the one-activity-many-fragments model, you may find that your activity's code gets really complicated dealing with all the possible configurations of fragments. That is a good sign that you may want to split it into multiple Activities. Similarly, if you go with the many-activities model, but find that things get complicated as you pass shared data between activities, consider merging the activities.
Converting from Activity to FragmentActivity is as simple as changing the extends and nothing else needs changing.
My conclusions:
I stopped using Activity and only use FragmentActivity as it is more flexible and more up to date and backwards compatible (Using the support library).
If the FragmentActivity has a component that is large enough to be a standalone component, or needs to be one, then I make it as Fragment.
I haven't come across something that would require a complete separate activity to be within another activity, but that should only be used if that component is large enough and completely standalone enough to need an activity for itself.
I don't fully understand your app to be able to make a specific call on which you should use, if you want my opinion, can you provide more details on what you are working on and how are those components connected.
Regards
Another consideration in choosing a more decomposed architecture (many Activities) might be the cost of destruction / creation in the Activity Lifecycle. Do you plan to use Explicit/Implicit intents to leverage existing apps? More death. So, you might have only one activity in a dispatch oriented model and clearly see your apps logic in one place, but how much state will you have to save/restore? Are there performance penalties for re-inflating or populating data resources?
I am working on a project, which at that stage will have to be customized for different customers. Application consists of some business logic and 15 different activities for the UI. Lets assume that activity A starts B, and B starts activity C. A knows about B, B knows about C. I want to be able to swap activity B (use different layout, a bit different logic to handle user interaction), but leave A and C intact. What is the best approach to achieve that? I will have more and more different activities (serving similar purpose) for different customers, so the solution needs to handle many different configurations.
I was planning on splitting customized activities to different libraries and using DI container (RoboGuice 2.0) to inject them, depending on configuration, but it looks like i still need to put all the activities in manifest.xaml, which requires double work (editing manifest + configuring DI container).
A knows about B, B knows about C.
That does not sound very wise in this case.
I want to be able to swap activity B (use different layout, a bit different logic to handle user interaction), but leave A and C intact.
Then put A, C, and all other common code in an Android library project. Put B and other customer-specific code in a customer-specific project that depends upon the library. Have some means for A (in the library) to determine how best to launch B (for the customer). For example, you could have all customer-specific projects advertise B with the same <intent-filter> (with a nice app-specific and otherwise obscure action string), and A can simply use an Intent that will match that filter for startActivity(). A then knows about B in a generic sense ("here's the B action") without knowing the B implementation, which would be customer-specific.
I was planning on splitting customized activities to different libraries and using DI container (RoboGuice 2.0) to inject them
That sounds like swatting a fly with a Buick, but perhaps you have a long history with DI.
but it looks like i still need to put all the activities in manifest.xaml, which requires double work (editing manifest + configuring DI container)
Drop the DI container, then.
Perhaps, instead of doing anything in your code, you could put your project under version control and, for some of your files, you can then have different branches for different customers.