How to manage dagger2 component creation and storage - android

A long time i have been struggling with dagger components.
At first i made Injectors class for each custom scoped component which contained static field either with WeakReference<Component> or just a Component, so that i always had an access to this component through static method.
But i think thats a pretty bad approach because WeakReference could be cleared so you will not get the same Component, as well as you can just forget to clear Component in static field.
I designed another approach when i have ComponentsHolder interface which is implemented by App and contains some methods to add, delete, and check if component exists in a HashMap<String, Component> inside the same App class.
So this approach combined with kotlin extensions for Context gave me a great opportunity to inject thing anywhere i have Context like this:
context.injector(Component::class) {
inject(this#ObjectWhereToInject)
}
So i mind maybe i doing something wrong? Or is there a better approach to store and retrieve dagger components?

Related

why we use private constructor in flutter sqlite databse

What is the use of this private constructor and why we instantiate it's object under the class.
DatabaseHelper._privateConstructor();
static final DatabaseHelper intance =DatabaseHelper._privateConstructor();
In general, we'll use a private constructor when we don't want things to be instantiated more than once. This lets us implement the singleton pattern:
https://www.geeksforgeeks.org/singleton-design-pattern/
In this case, we don't want multiple instance of the database. So, it'll instantiate the database if it hasn't already been instantiated, or it'll return the existing instance of the database if it has been instantiated previously.
It is a design pattern called the singleton pattern.
It's main purpose is to ensure that only one instance of that class ever exists in the application.
To ensure this purpose, the pattern implements techniques that have serious disadvantages. People are overusing it, sometimes using it as a justification as to why they have those disadvantages in their program that would otherwise be considered bad design. It has become an anti-pattern. See Why is Singleton considered an anti-pattern?.
In addition to given answers, it is Eager singleton, therefore once the class is initialized, the instance is also initialized, even the instance is not used. However still it has been instantiated only once.
See also Singleton lazy vs eager instantiation
As the other answers state, it's the singleton pattern. Here's a link that explains it more.

How to inject into dynamically created use cases (android, clean architecture, dagger2)

I'm creating an Android app and want to comply to clean architecture.
For example, I have an activity which has a presenter which creates use cases. In that inner layer, I have a repository interface (which is known by the use cases) which is implemented by a concrete repository, lets call it repsoitoryImpl (which is not known by the uses cases). What I did in previous projects was to create the presenter and the repositoryImpl in the activity, and pass the repositoryImpl as a repository to the presenter. The presenter can then, whenever there is an action coming from the activity (e.g. a button press) create a new use case and pass the repository to it.
This works, but a) the constructors of the use cases can become very long and b) the UI has knowledge of all other "outer" things, e.g. the repositoryImpl. So I thought DI to the rescue! And started to try out Dagger 2. However, my current solution does not seem to be "correct". What I would have liked is that I can just have an #inject annotated repository in a usecase and a repositoryImpl gets injected. However I found that, at the beginning of the "injection chain" I have to call inject() on the dagger component. In most of the examples, this is done in the activity. But then I would have to inject the presenter in the activity and the usecase into the presenter to be able to inject things into the use case. Is this correct? The problem is that I want to create the use cases dynamically with different parameters and not inject them.
So my current solution is to have the dagger "AppComponent" as a static field in the Android Application class and then in my use cases I call
Application.component.inject(this)
which allows me to inject things in the use case. But then the use cases have a dependency to dagger which doesn't comply to clean architecture. Because framework dependencies should only appear in the outer layer.
Is there a common solution to this problem? Am I understanding something wrong?
As u already pointed out in clean architecture use cases must not know about DI frameworks - even decorating use cases with framework specific attributes would be a smell.
As discussed here: How to handle UseCase Interactor constructors that have too many dependency parameters in DDD w/ Clean Architecture? having too many constructor parameters is usually an indicator that the use case is "doing too much". U should consider splitting them.
Furthermore the interfaces used by a use case to access "the details" (repository, external services and systems) should be designed in a way that they are most convenient for the use case. That means instead of having multiple repository interfaces and multiple service interfaces passed to a use case u could consider using façade pattern and design one or two interfaces which are more convenient for the use cases which then "aggregate" the work with the different repositories/services. This will also reduce the number of parameters passed to the constructor.
According to clean architecture the "composition" of ur application happens in the "main component" - a class living in the frameworks circle. There are objects are created and injected. If u want to create use cases dynamically u could have a factory pattern.

Context in MVVM in android

I have started working on MVVM architecture for android application.I have a doubt that is it right to pass the context to view model ? If not then how can my view model can access the context if needed.
I am doing the following things:
Feed data using some EditText.
Send this data to View model.
View model send this data to repository
Repository storing this data to shared preferences of the device.
As shared preferences required context to instantiate the object.
I am new to this architecture any guidance would be helpful for me, thanks in advance.
I think the use of ApplicationContext is ok, You can extend your ViewModel from AndroidViewModel and whenever you need a reference to the context use getApplication() methods.
Even better, if your using dagger, you don't need this at all, you just inject your ApplicationContext where ever you need it. It can be in your view model or a utility class that handles shared preference, etc.
UPDATE 2019
I don't want to mislead anyone with my old post, so figured I better update it.
With the latest release of the architectural components and JetPack, MVVM is now a real competitor for actual proper structure of breaking apart the code base in a very clean way.
The View is the Activity or Fragment along with the xml that is inflated basically (that's a bit of a weird MVVM, I know, but let's roll with it).
The ViewModel is the actual ViewModel classes offered now with lifecycle scopes and observers. Due to these new features, and life cycle management tools, the ViewModel is very nice at maintaining the data for the view while accessing the Repository Layer of Room DB or Retro API for fetching appropriate LiveData, Observable Data or just standard Models.
I'll leave this here as I feel it was very relevant during the earlier pre Architecture Implementation Days, but if you are not using the Architecture Components and JetPack, Boy are you missing out lol. Code is getting so much cleaner and smaller. :)
OLD REPLY
This is a long debated discussion among the Android community. When we refer to MVC it is obvious that Models (aka data holding objects) are the M, Controllers = C for the Activity classes (in iOS they actually call them UIViewControllers) and the V for the View in Android is the XML file itself. Now some would argue the architectural breakdown of what represents what. However, let's move past this and discuss MVVM.
MVVM has been around for many years now. There have been a few attempts in the past to bring it to Android through 3rd party binding tools, but it ends up more hacky then it is worth.
Recently with the release of native Data Binding Android is finally capable of doing a somewhat clean implementation of MVVM. So there are a couple options here. You can do
M = Models (data holding objects)
V = Views (the XML file itself representing the UI)
VM = This is where debates occur.
Some say in order to be a "true" ViewModel one must have true separation from the Presentation layer and the Activity class itself has lifecycle callbacks thus making it unworthy of being known as the ViewModel.
Others would point out that in order to handle most of the actions triggered from the ViewModel one must have an awareness of onActivityResult, onNewIntent, onBroadcastReceived, onPause or other life cycle handlings to appropriately manage the user experience. So On my team we consider the Activity as the ViewModel. Otherwise you are passing the activity down to a viewmodel and tightly coupling the two anyways, making a giant hideous maintenance nightmare of code.
So you if you want my opinion, stick to treating the Activity as your ViewModel. Get your data to the ViewModel just like any other binding technology like INotifyPropertyChanged in WPF. You do it through your Binding.
I do two things to make this happen. One I have an Activity variable in the XML layout to inject in the onCreate for the binding setup which gives the XML direct binding rights to any observable properties in the viewModel aka the activity. Then I inject whatever variables I need to make use of as well for example you may have a WeatherModel that populates a forecast that lives within the Activity that you would also set in the onCreate to allow the XML access to both it's ViewModel (aka activity) and it's viewModel's Objects.
The other alternative is to make a ViewModel object and inject it in the XML in the onCreate of your Activity and then continue to call back and forth from the activity to the viewmodel for handling actions and lifecycles and feel free to manage that nightmare haha, I did an entire project this way and by the end of it, I redid it all to avoid all the duplication of coding efforts and hideous back and forths.
Goodluck and I hope that helps.
A very good question, and it is not as simple as it seems!
You can see an example from Google team here.
They solved the problem with the help of the factory.
There it is pass (of course) the Application context (not Activity context !).
A small problem - and so much boilerplate code!
My decision:
public class MainApplication extends Application {
public void onCreate() {
AppSharedPref sharedPref = AppSharedPref.getInstance(PreferenceManager.getDefaultSharedPreferences(this));
AppRepository.getInstance(sharedPref);
Repository is singltone (a lot of code is skipped for brevity):
public class AppRepository implements AppDataSource {
public static AppRepository getInstance(#NonNull AppSharedPref sharedPref) {
if (INSTANCE == null) {
INSTANCE = new AppRepository(sharedPref);
}
return INSTANCE;
}
In ViewModel call:
public class MyViewModel extends AndroidViewModel {
// constructor
public MyViewModel(#NonNull Application application) {
repository = AppRepository.getInstance(.....);
}
Look into Dagger 2!
That's true , you definitively shouldn't pass Activity to your xml or ViewModel. It will make your ViewModel no better than these 2000-line activities that we are trying to move away from with this architecture.
The solution we have in our MVVM project is to inject SharedPreferences with Dagger. You can of corse use ApplicationContext as well but do you need multiple instances of SharedPreferences in the project??
We a have a utility class for SharedPreferences and it is nice to keep it a singleton and inject wherever you need it.
I use MVVM in my application. I always try not to use Context inside my View Model. I also encountered the problem with SharedPreferences requiring a context to access the preference files. One of my solutions without using Dagger is to create a Preference utility class that will have reference to the application context. You initialize this utility class in you Application class. You get reference to the shared preference through a public static method provided by the utility class. You can directly call the utility class from your repository class. I prefer to contain all logic related to data storage in the repository class that's why i call the sharedpreference utility class in my repository class.
PreferenceManager.java
public class PreferenceManager {
private static SharedPreferences mSharedpreferences;
private PreferenceManager() {}
public static void initialize(Context context) {
mSharedpreferences= context.getSharedPreferences(context.getPackageName(),
Context.MODE_PRIVATE);
}
public static SharedPreferences getSharedPreferences() {
return mSharedpreferences;
}
}
App.java
public class App extends Application {
#Override
public void onCreate() {
PreferenceManager.initialize(this);
}
}
Repository.java
public class Repository {
public void someMethod() {
PreferenceManager.getSharedPreferences.edit.putBoolean("sample", true).apply();
}
You should use AndroidViewModel() in the ViewModel, pass application:Applicatoin, and use getApplication() to get the context.
ViewModel Example:
class MainTrendsViewModel (application: Application) : AndroidViewModel(application) {
// ViewModel must extend AndroidViewModel(), and pass application to it.
// Code here and
// use getApplication() to get context
}
Other anwer that work for me that you could reference: reference answer that works for me
You should use AndroidViewModel class or keep reference to Application context in yours ViewModel implementation in this case.
ViewModel class was designed to keep data persistent between different instances of Activity through its lifecircle and storing reference to one of Activity instance context really doesn't make sense.

Two activities access same variable

I was wondering if I have 2 activities that needs to update and access the same object . What would be the best way to do it? Should I use Application class? Or perhaps Static variable.. Etc?
Another option I can think of is putting it in a base class that both activities inherit. I will initialize the object from shared preferences during OnResume
If your object holds some kind of preference value, don't put it into a super-class. Make it static and/or use the singleton pattern and separate it from your application logic. This provides you with a more modular structure that will be easier to work with. The application class is probably overkill; singletons do the job most of the time. (The Android docs simply states: "There is normally no need to subclass Application.")
You can add it to a super-class, if it is a logical part of it though.
Don't forget to synchronize your object if it's going to be accessed by another/several thread(s).
There are different method to perform such requirement. Singleton is one of them. The other one is extending the application class. If you want a reference outlining all of these methods please see:
What's the best way to share data between activities?

can Dagger be used to perform injection on a Content Provider?

I have recently been integrating Dagger into a project that uses ContentProviders. I create a single ObjectGraph instance in my custom Application object, and basically in each managed component:
Activity,
Fragment,
Service
... Then, I call getApplication(), downcast to my custom Application object, and force the injection through some custom implementation in my Application class. This seems to be the prescribed method of performing injection based on the samples I've seen posted by the guys at Square.
This pattern doesn't hold for ContentProvider instances though as their lifecycle isn't as predictably tied to the lifecycle of the Application object, ie ContentProviders can be, and as I'm observing frequently are, created before the Application object is created (for reasons I have yet to comprehend).
so... does anyone have a nice way of injecting ContentProviders using Dagger? I've so far made it by having an isInjected() call at the beginning of each of my ContentProvider's interface methods (insert, query, update, delete)... basically a hacky form of lazy initialization. But this seems far from ideal. Is there a more prescribed approach to injecting ContentProviders?
The Application subclass is just a convention since it's usually the first object created. Our apps do not have content providers which is why we use them. There's nothing that says you can't put it somewhere else.
You can just use the traditional singleton pattern for instantiating and holding a reference to the ObjectGraph.
public final class Dagger {
static ObjectGraph og;
static ObjectGraph og() {
if (og == null) {
og = ObjectGraph.create(..);
}
return og;
}
}
The first person to access will initialize the instance which will be used for the lifetime of the process.
If your content provider is in a different process than your main application this solution will still work. Or you could simply create the graph when your content provider is created since it will be the only consumer. Normal multi-process rules still apply, of course, so no instances will be shared with the other processes.

Categories

Resources