Inject in Dagger returns null - java

Been blocked on this for a number of days.
For some reason my the 'application' member field in AndroidModule.java is null after injection.
AndroidModule.java
#Module(
library = true
)
public class AndroidModule {
#Inject MittoApplication application;
#Provides #Singleton
SharedPreferences provideSharedPreferences() {
return PreferenceManager.getDefaultSharedPreferences( application );
}
}
ApplicationModule.java
#Module(
includes = { ApiModule.class, AndroidModule.class },
library = true
)
public class ApplicationModule {
private Application application;
public ApplicationModule( Application application ) {
this.application = application;
}
#Provides #Singleton
Application providesApplication() {
return application;
}
}
BaseActivity.java
public class BaseActivity extends AppCompatActivity {
private ObjectGraph objectGraph;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
objectGraph = MittoApplication.getApplication(this).buildScopedObjectGraph(getModules());
objectGraph.inject(this);
}
#Override
protected void onDestroy() {
objectGraph = null;
super.onDestroy();
}
protected List<Object> getModules( ) {
return Arrays.<Object>asList(
);
}
}
MittoApplication.java
public class MittoApplication extends Application {
private static Context context;
private ObjectGraph objectGraph;
public void onCreate() {
super.onCreate();
MittoApplication.context = getApplicationContext();
initializeObjectGraph();
}
public static MittoApplication getApplication( Context context ) {
MittoApplication mittoApplication = (MittoApplication) context.getApplicationContext();
return mittoApplication;
}
public ObjectGraph getObjectGraph() {
return this.objectGraph;
}
public ObjectGraph buildObjectGraph( List<Object> modules ) {
return ObjectGraph.create(modules.toArray() );
}
public ObjectGraph buildScopedObjectGraph( List<Object> modules ) {
return objectGraph.plus(modules.toArray() );
}
private ObjectGraph buildInitialObjectGraph( List<Object> modules ) {
return ObjectGraph.create( modules.toArray() );
}
private void initializeObjectGraph() {
objectGraph = buildInitialObjectGraph( Arrays.<Object>asList( new ApplicationModule(this) ));
}
public static Context getContext() {
return MittoApplication.context;
}
}
I've spend ages pondering over this, I've looked at countless examples and blog sites. Would love someone smarter then I to assist.
Thanks for reading.

Field injection works only with direct invocation of the object graph. To obtain the application instance for your provider method, you need to reference it as a parameter of the provider method.
//#Inject MittoApplication application; //this won't work
#Provides #Singleton
SharedPreferences provideSharedPreferences(Application application) { //this will
return PreferenceManager.getDefaultSharedPreferences( application );
}
Also, you never actually provided a MittoApplication, only an Application.
And it's worth noting that you are using Dagger1, so I believe you will need to change your AndroidModule to be complete=false:
#Module(
library = true,
complete = false
)
public class AndroidModule {

Related

How to get a singleton injection in a class with Dagger in android

There is the DataAccessInterface class that is in charge of managing the database:
public class DataAccessInterface {
private DaoSession daoSession;
public DataAccessInterface () {
}
...
public void saveCar (Car car) {
daoSession.getCarDao (). insert (car);
}
}
DataAccessInterface injection is used in several Fragments with success. Example:
public class LoginFragment extends BaseFragment {
#Inject
DataAccessInterface dataAccessInterface;
...
public boolean initDatabase () throws SyncDataBaseException {
try {
dataAccessInterface.openSession (currentUser.getUsername ());
} catch (Exception e) {
throw new SyncDataBaseException ();
}
return true;
}
...
}
There is a BackendImp class (No Fragment or Activity) that in the background queries a rest service and saves the response in the database. The injection does not work, it is always null:
public class BackendImp {
#Inject
DataAccessInterface dataAccessInterface;
public void save () {
Car car = unloadCar ()
dataAccessInterface.saveCar (car);
}
The AbstractActivityComponent looks like this
#PerActivity
#Component (dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface AbstractActivityComponent {
Activity activity ();
final class Initializer {
public static AbstractActivityComponent init (Activity activity) {
return DaggerAbstractActivityComponent.builder ()
.applicationComponent (DaggerManager.getInstance (). appComponent ())
.activityModule (new ActivityModule (activity))
.build ();
}
}
void inject (LoginFragment inject);
void inject (BackendImp inject);
}
ApplicationModule:
#Module
public class ApplicationModule {
private final Application application;
private final User currentUser;
public ApplicationModule (Application application) {
this.application = application;
this.currentUser = getUser ();
}
#Provides
#Singleton
DataAccessInterface dataAccessInterface () {
return new DataAccessInterface (userProfile ());
}
}
And ApplicationComponent
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(Application application);
final class Initializer {
public static ApplicationComponent init(Application app) {
return DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(app))
.build();
}
}
Application application();
Context context();
DataAccessInterface dataAccessInterface();
}
Error:
W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.service.DataAccessInterface.saveCar(Car)' on a null object reference
Edit:
Based on Nitrodon's question in the comments:
The BackendImp functions are called from a Worker, since they will be done every hour. I wanted a single instance so I did the following which is probably wrong:
public class MainApp extends Application {
public static BackendService backendService;
#Override
public void onCreate () {
super.onCreate ();
backendService = new BackendImp ();
}
public static void callWorker () {
...
workManager.enqueue (updateWorkRequest);
}
And the Worker:
public class updateWorker extends Worker {
...
#Override
public Result doWork () {
Result result = Result.retry ();
try {
backend = MainApp.backendService;
backend.save ();
result = Result.success ();
} catch (Exception e) {
result = Result.retry ();
}
return result;
}
Dagger doesn't hook into constructor calls. You have to tell Dagger to inject dependencies into BackendImp.
You have an inject(BackendImp inject) method in your activity component. This would work, but it's in the wrong place, so your application class can't access it. Putting this method in the application component would work:
#Override
public void onCreate () {
super.onCreate ();
backendService = new BackendImp();
// I assume you created the application component somewhere in here.
component.inject(backendService);
}
However, members injection methods are generally discouraged where they can be avoided. There's no other choice in Activity subclasses, since they are instantiated by the framework, but something like BackendImp is entirely under your control, so you can and should let Dagger create it for you.
To do this, place BackendImp itself in the application component by giving it the #Singleton scope and an #Inject constructor:
#Singleton
public class BackendImp {
final DataAccessInterface dataAccessInterface;
#Inject
BackendImp(DataAccessInterface dataAccessInterface) {
this.dataAccessInterface = dataAccessInterface;
}
// ...
}
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
// ...
// Use this in your application instead of new BackendImp()
BackendImp backendImp();
// Many tutorials instead suggest making an #Inject field in
// your application and calling inject(application).
}

Android Architecture SingleLiveEvent and EventObserver Practicle Example in Java

I try to make sample login page with two fields (username, password) and save button with android architecture component, using android data binding, validating the data in viewmodel and from view model I make call to repository for remote server call as mentioned in official doc, remote server return me userid with success so how can I start new fragment from view model using this success? I learn something about singleLiveEvent and EventObserver, but I'm not able to find there clear usage example:
LoginViewModel
private MutableLiveData<String> snackbarStringSingleLiveEvent= new MutableLiveData<>();
#Inject
public LoginViewModel(#NonNull AppDatabase appDatabase,
#NonNull JobPortalApplication application,
#NonNull MyApiEndpointInterface myApiEndpointInterface) {
super(application);
loginRepository = new LoginRepository(application, appDatabase, myApiEndpointInterface);
snackbarStringSingleLiveEvent = loginRepository.getLogin(username.get(), password.get(), type.get());
}
public MutableLiveData<String> getSnackbarStringSingleLiveEvent() {
return snackbarStringSingleLiveEvent;
}
Repository
public SingleLiveEvent<String> getLogin(String name, String password, String type) {
SingleLiveEvent<String> mutableLiveData = new SingleLiveEvent<>();
apiEndpointInterface.getlogin(name, password, type).enqueue(new Callback<GenericResponse>() {
#Override
public void onResponse(Call<GenericResponse> call, Response<GenericResponse> response) {
mutableLiveData.setValue(response.body().getMessage());
}
#Override
public void onFailure(Call<GenericResponse> responseCall, Throwable t) {
mutableLiveData.setValue(Constant.FAILED);
}
});
return mutableLiveData;
}
Login Fragment
private void observeViewModel(final LoginViewModel viewModel) {
// Observe project data
viewModel.getSnackbarStringSingleLiveEvent().observe(this, new Observer<String>() {
#Override
public void onChanged(String s) {
}
});
}
How can I use EventObserver in above case? Any practical example?
Check out below example about how you can create single LiveEvent to observe only one time as LiveData :
Create a class called Event as below that will provide our data once and acts as child of LiveData wrapper :
public class Event<T> {
private boolean hasBeenHandled = false;
private T content;
public Event(T content) {
this.content = content;
}
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return content;
}
}
public boolean isHandled() {
return hasBeenHandled;
}
}
Then declare this EventObserver class like below so that we don't end up placing condition for checking about Event handled every time, everywhere :
public class EventObserver<T> implements Observer<Event<T>> {
private OnEventChanged onEventChanged;
public EventObserver(OnEventChanged onEventChanged) {
this.onEventChanged = onEventChanged;
}
#Override
public void onChanged(#Nullable Event<T> tEvent) {
if (tEvent != null && tEvent.getContentIfNotHandled() != null && onEventChanged != null)
onEventChanged.onUnhandledContent(tEvent.getContentIfNotHandled());
}
interface OnEventChanged<T> {
void onUnhandledContent(T data);
}
}
And How you can implement it :
MutableLiveData<Event<String>> data = new MutableLiveData<>();
// And observe like below
data.observe(lifecycleOwner, new EventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
// And this is how you add data as event to LiveData
data.setValue(new Event(""));
Refer here for details.
Edit for O.P.:
Yes, data.setValue(new Event("")); is meant for repository when you've got response from API (Remember to return same LiveData type you've taken in VM instead of SingleLiveEvent class though).
So, let's say you've created LiveData in ViewModel like below :
private MutableLiveData<Event<String>> snackbarStringSingleLiveEvent= new MutableLiveData<>();
You provide value to this livedata as Single Event from repository like below :
#Override
public void onResponse(Call<GenericResponse> call, Response<GenericResponse> response) {
mutableLiveData.setValue(new Event(response.body().getMessage())); // we set it as Event wrapper class.
}
And observe it on UI (Fragment) like below :
viewModel.getSnackbarStringSingleLiveEvent().observe(this, new EventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
Event.java
public class Event<T> {
private T content;
private boolean hasBeenHandled = false;
public Event(T content) {
this.content = content;
}
/**
* Returns the content and prevents its use again.
*/
public T getContentIfNotHandled() {
if (hasBeenHandled) {
return null;
} else {
hasBeenHandled = true;
return content;
}
}
/**
* Returns the content, even if it's already been handled.
*/
public T peekContent() {
return content;
}
}
EventObserver.java
public class EventObserver<T> implements Observer<Event<? extends T>> {
public interface EventUnhandledContent<T> {
void onEventUnhandledContent(T t);
}
private EventUnhandledContent<T> content;
public EventObserver(EventUnhandledContent<T> content) {
this.content = content;
}
#Override
public void onChanged(Event<? extends T> event) {
if (event != null) {
T result = event.getContentIfNotHandled();
if (result != null && content != null) {
content.onEventUnhandledContent(result);
}
}
}
}
Example, In ViewModel Class
public class LoginViewModel extends BaseViewModel {
private MutableLiveData<Event<Boolean>> _isProgressEnabled = new MutableLiveData<>();
LiveData<Event<Boolean>> isProgressEnabled = _isProgressEnabled;
private AppService appService;
private SchedulerProvider schedulerProvider;
private SharedPreferences preferences;
#Inject
LoginViewModel(
AppService appService,
SchedulerProvider schedulerProvider,
SharedPreferences preferences
) {
this.appService = appService;
this.schedulerProvider = schedulerProvider;
this.preferences = preferences;
}
public void login(){
appService.login("username", "password")
.subscribeOn(schedulerProvider.executorIo())
.observeOn(schedulerProvider.ui())
.subscribe(_userLoginDetails::setValue,
_userLoginDetailsError::setValue,
() -> _isProgressEnabled.setValue(new Event<>(false)),
d -> _isProgressEnabled.setValue(new Event<>(true))
)
}
}
In Login Fragment,
viewModel.isProgressEnabled.observe(this, new EventObserver<>(hasEnabled -> {
if (hasEnabled) {
// showProgress
} else {
// hideProgress
}
}));
Using Event and EventObserver class we can achieve the same like SingleLiveEvent class but if you are thinking a lot of boilerplate code just avoid this method. I hope it would help you and give some idea about why we are using SingleEvent in LiveData.
I understand that Google gives the guidelines to use LiveData between the ViewModel and UI but there are edge cases where using LiveData as a SingleLiveEvent is like reinventing the wheel. For single time messaging between the view model and user interface we can use the delegate design pattern. When initializing the view model in the activity we just have to set the activity as the implementer of the interface. Then throughout our view model we can call the delegate method.
Interface
public interface Snackable:
void showSnackbarMessage(String message);
UI
public class MyActivity extends AppCompatActivity implements Snackable {
private MyViewModel myViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
this.myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
this.myViewModel.setListener(this);
}
#Override
public void showSnackbarMessage(String message) {
Toast.makeText(this, "message", Toast.LENGTH_LONG).show();
}
}
View Model
public class MyViewModel extends AndroidViewModel {
private Snackable listener;
public MyViewModel(#NonNull Application application) {
super(application);
}
public void setListener(MyActivity activity){
this.listener = activity;
}
private void sendSnackbarMessage(String message){
if(listener != null){
listener.showSnackbarMessage(message);
}
}
private void anyFunctionInTheViewModel(){
sendSnackbarMessage("Hey I've got a message for the UI!");
}
}

How to Inject a SharedPreferences Class as DataManager into app?

I'm getting this error while i'm trying to Build/Rebuild :
error: ir.atlaspio.roshdbookstore.DI.Components.ApplicationComponent scoped with #ir.atlaspio.roshdbookstore.DI.Scopes.ApplicationScope may not reference bindings with different scopes:
#Singleton class ir.atlaspio.roshdbookstore.Data.Prefs.AtlasPreferencesHelper
I'm trying to improve my code base on some projects and tutorials, right now i'm trying to doing dependency injection for SharedPreferences, which i've got above problem. It's not long time since i'm messing with Dagger 2 And DI, so excuse my beginner question and help me about this to find out where i'm doing this wrong. also there are some codes which they will inject SharedPrefereces but what i want is to use My own DataManager to do it right.
So here's how i created my project(Which is base on some tutorials):
Explaining Section(Which could be obvious for you guys): adding some method to set data into sharedpref.
AtlasPreferencesHelper :
#Singleton
public class AtlasPreferencesHelper implements PreferencesHelper {
private static final String PREF_KEY_USER_LOGGED_IN_MODE = "PREF_KEY_USER_LOGGED_IN_MODE";
private static final String PREF_KEY_FIRST_TIME_RUN_MODE = "PREF_KEY_FIRST_TIME_RUN_MODE";
private final SharedPreferences atlasPrefs;
#Inject
public AtlasPreferencesHelper(#ApplicationContext Context context,
#PreferenceInfo String prefFileName) {
atlasPrefs = context.getSharedPreferences(prefFileName, Context.MODE_PRIVATE);
}
#Override
public int getCurrentUserLoggedInMode() {
return atlasPrefs.getInt(PREF_KEY_USER_LOGGED_IN_MODE,
DataManager.LoggedInMode.LOGGED_IN_MODE_LOGGED_OUT.getType());
}
#Override
public void setCurrentUserLoggedInMode(DataManager.LoggedInMode mode) {
atlasPrefs.edit().putInt(PREF_KEY_USER_LOGGED_IN_MODE, mode.getType()).apply();
}
#Override
public int getCurrentFirstTimeStat() {
return atlasPrefs.getInt(PREF_KEY_FIRST_TIME_RUN_MODE,
DataManager.FirstTimeRun.FIRST_TIME_RUN_TRUE.getFrType());
}
#Override
public void setCurrentFirstTimeStat(DataManager.FirstTimeRun fMode) {
atlasPrefs.edit().putInt(PREF_KEY_FIRST_TIME_RUN_MODE, fMode.getFrType()).apply();
}
}
Explains : interface to be implemented in AtlasPreferencesHelper.
PreferenceHelper :
public interface PreferencesHelper {
int getCurrentUserLoggedInMode();
void setCurrentUserLoggedInMode(DataManager.LoggedInMode mode);
int getCurrentFirstTimeStat();
void setCurrentFirstTimeStat(DataManager.FirstTimeRun fMode);
}
Explains: Doing Job and getting access to activity to use methods.
AppDataManager :
public class AppDataManager implements DataManager {
private static final String TAG = "AppDataManager";
private final Context mContext;
private final PreferencesHelper mPrefencesHelper;
#Inject
public AppDataManager(#ApplicationContext Context context, PreferencesHelper prefencesHelper) {
mContext = context;
mPrefencesHelper = prefencesHelper;
}
#Override
public void setUserAssLoggedOut() {
setCurrentUserLoggedInMode(LoggedInMode.LOGGED_IN_MODE_LOGGED_OUT);
}
#Override
public int getCurrentUserLoggedInMode() {
return mPrefencesHelper.getCurrentUserLoggedInMode();
}
#Override
public void setCurrentUserLoggedInMode(LoggedInMode mode) {
mPrefencesHelper.setCurrentUserLoggedInMode(mode);
}
#Override
public int getCurrentFirstTimeStat() {
return mPrefencesHelper.getCurrentFirstTimeStat();
}
#Override
public void setCurrentFirstTimeStat(FirstTimeRun fMode) {
mPrefencesHelper.setCurrentFirstTimeStat(fMode);
}
}
Explains : DataManager interface implemented to AppDataManager
DataManager :
public interface DataManager extends PreferencesHelper {
void setUserAssLoggedOut();
enum LoggedInMode {
LOGGED_IN_MODE_LOGGED_OUT(0),
LOGGED_IN_MODE_SERVER(1);
private final int mType;
LoggedInMode(int type)
{
mType = type;
}
public int getType()
{
return mType;
}
}
enum FirstTimeRun {
FIRST_TIME_RUN_FALSE(0),
FIRST_TIME_RUN_TRUE(1);
private final int frType;
FirstTimeRun(int rType){
frType = rType;
}
public int getFrType()
{
return frType;
}
}
}
Explains : Components which, Context provide context, Retrofit Provide retrofit and SharedPref will provide Datamanager and SharedPref
ApplicationComponent :
#ApplicationScope
#Component(modules = {ContextModule.class,
RetrofitModule.class,
SharedPrefModule.class})
public interface ApplicationComponent {
MyAtlasAPI getApiReference();
DataManager getDataManager();
#ApplicationContext
Context getContext();
void injectApplication(AtlasApplication atlasApplication);
}
Explains : Module that will be implement in component for datamanager and sharedpref
SharedPrefModule :
#Module
public class SharedPrefModule {
#Provides
#PreferenceInfo
String providePreferenceName() {
return AppConstants.PREF_NAME;
}
#Provides
#Singleton
DataManager provideDataManager(AppDataManager appDataManager)
{
return appDataManager;
}
#Provides
#Singleton
PreferencesHelper providePreferencesHelper(AtlasPreferencesHelper atlasPreferencesHelper)
{
return atlasPreferencesHelper;
}
}
The error you're getting is telling it all. You're trying to reference to a module with a different scope than your component.
Looking at you ApplicationComponent:
#ApplicationScope
#Component(modules = {ContextModule.class,
RetrofitModule.class,
SharedPrefModule.class})
public interface ApplicationComponent { }
It's using the ApplicationScope
Your ApplicationComponent is then referring to SharedPrefModule.
If we take a look at that class:
#Module
public class SharedPrefModule {
#Provides
#Singleton
PreferencesHelper providePreferencesHelper(AtlasPreferencesHelper atlasPreferencesHelper) {
return atlasPreferencesHelper;
}
}
This module is using the Singleton scope.
Finally your AtlasPreferencesHelper is also scoped with Singleton:
#Singleton
public class AtlasPreferencesHelper {}
What you wanna do is align these scopes.
So either annotate the ApplicationComponent with #Singleton or use the #Application for all the modules within your ApplicationComponent

Is there a difference between the way Dagger2 treats #Singleton and custom sopes?

The question is in the subject, yet I'll repeat it again:
Is there a difference between the way Dagger2 treats #Singleton and custom sopes?
Also, if a class is annotated with some scope, is there a convenient way to expose it as a different scope (or unscoped), or do I need to write a provider method?
There is no difference between the way Dagger2 treats #Singleton and custom sopes.
Lets say we are using #User
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface User {
}
#Module
public class TwitterModule {
private final String user;
public TwitterModule(String user) {
this.user = user;
}
#Provides
#User
Tweeter provideTweeter(TwitterApi twitterApi) {
return new Tweeter(twitterApi, user);
}
#Provides
#User
Timeline provideTimeline(TwitterApi twitterApi) {
return new Timeline(twitterApi, user);
}
}
#Module
public class NetworkModule {
#Provides
#Singleton
OkHttpClient provideOkHttpClient() {
return new OkHttpClient();
}
#Provides
#Singleton
TwitterApi provideTwitterApi(OkHttpClient okHttpClient) {
return new TwitterApi(okHttpClient);
}
}
#Singleton
#Component(modules = {NetworkModule.class})
public interface ApiComponent {
TwitterApi api();
TwitterComponent twitterComponent(TwitterModule twitterModule);
}
#User
#Subcomponent(modules = {TwitterModule.class})
public interface TwitterComponent {
TwitterApplication app();
}
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
TwitterComponent twitterComponentForUserOne,twitterComponentForUserTwo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ApiComponent apiComponent = DaggerApiComponent.create();
twitterComponentForUserOne = apiComponent.twitterComponent(new TwitterModule("Amit Shekhar"));
twitterComponentForUserTwo = apiComponent.twitterComponent(new TwitterModule("Sumit Shekhar"));
// use twitterComponentOne and twitterComponentTwo for two users independently
}
#Override
protected void onDestroy() {
super.onDestroy();
twitterComponentForUserOne = null;
twitterComponentForUserTwo = null;
}
}
Here just we have to make sure that when we do not need the twitterComponent for that user. We have to assign null so that it gets garbage collected as I am doing here in onDestroy();
Finally, everything depends on component,if you have an instance of component in Application class it is not going to be garbage collected for whole application life-cycle.

Dagger dependency injection

Actually i am new to dependency injection and dagger, i have been writing boiler plate code all these time and am trying to learn dagger
I have a global class to save preference values
#Module(injects = AppPrefes.class)
public class AppPrefes {
private SharedPreferences appSharedPrefs;
private Editor prefsEditor;
public AppPrefes(Context context, String Preferncename) {
this.appSharedPrefs = context.getSharedPreferences(Preferncename,
Activity.MODE_PRIVATE);
this.prefsEditor = appSharedPrefs.edit();
}
/****
*
* getdata() get the value from the preference
*
* */
#Provides
public String getData(String key) {
return appSharedPrefs.getString(key, "");
}
/****
*
* SaveData() save the value to the preference
*
* */
#Provides
public void SaveData(String Tag, String text) {
prefsEditor.putString(Tag, text);
prefsEditor.commit();
}
}
How could i possibly inject this class in My activity
In my activity oncreate i have put like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ObjectGraph objectGraph = ObjectGraph.create();
AppPrefes app = objectGraph.get(AppPrefes.class);
}
but how should i pass dependency i.e the context and the preference name to AppPrefes class,i am completely new to dependency injection please correct me if i am wrong
Since dagger documentation seems to be little tough for me am asking this question.
I believe if you are willing to take the risk of creating a static variable to store the instance of the application,
public enum ApplicationHolder
{
INSTANCE;
private MyApplication application;
public MyApplication getApplication()
{
return application;
}
public void setApplication(MyApplication application)
{
this.application = application;
}
}
public MyApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
ApplicationHolder.INSTANCE.setApplication(this);
objectGraph.create(new RootModule());
}
}
Afterwards, you can create a Dagger module which can provide the Context of the Application instance.
#Module(complete = false, library = true)
public class ContextModule
{
#Provides
public Context providesContext()
{
return ApplicationHolder.INSTANCE.getApplication().getApplicationContext();
}
}
#Module(
includes =
{
ContextModule.class
},
injects =
{
AppPrefes.class
}
)
public class RootModule
{
}
Then you can inject this in your Activity with #Inject, however you need to provide the String you want to inject as a constructor parameter like this: https://stackoverflow.com/a/18105271/2413303
The structure of modules and stuff for me were like here: How to set up DAGGER dependency injection from scratch in Android project?

Categories