Dependency Injection with Dagger2, how to get context - android

I'm learning dependency injection with Dagger2.
I created a HttpRequester class that has a get method and returns some data from a server.
This is my code:
MainActivity
public class MainActivity extends AppCompatActivity {
#Inject
HttpRequester httpRequester;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getHttpRequester();
httpRequester.get("http://url.to.get.the.data", new HttpRequester.Listener() {
#Override
public void onDataRetrieved(String result) {
Log.d("App", "Result: " + result);
}
});
}
#Override
protected void onStop () {
super.onStop();
if (httpRequester != null) {
httpRequester.cancelAll();
}
}
void getHttpRequester() {
HttpRequesterComponent httpRequesterComponent = DaggerHttpRequesterComponent.builder().httpRequesterModule(new HttpRequesterModule()).build();
httpRequester = httpRequesterComponent.provideHttpRequester();
}
}
HttpRequesterModule
#Module
public class HttpRequesterModule {
#Provides #Singleton
HttpRequester provideHttpRequester(Context context){
return new HttpRequester(context);
}
}
HttpRequesterComponent
#Singleton
#Component(modules = {HttpRequesterModule.class})
public interface HttpRequesterComponent {
HttpRequester provideHttpRequester();
}
HttpRequester
public class HttpRequester {
Context context;
public HttpRequester(Context context) {
this.context = context;
}
public interface Listener {
void onDataRetrieved(String result);
}
private RequestQueue queue = Volley.newRequestQueue(context);
public static final String TAG = "TAG";
public void get(String url, final Listener listener){
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String res) {
listener.onDataRetrieved(res);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
});
stringRequest.setTag(TAG);
queue.add(stringRequest);
}
public void cancelAll() {
queue.cancelAll(TAG);
}
}
The problem is that when I call httpRequester.get() I get a NullPointerException since the context is null. I want to know how to inject the context. Thanks for your help!

You have to notice that you never initialize the context attribute con HttpRequester. Receive a Context in your constructor so it has a value:
public class HttpRequester {
Context context;
public HttpRequester(Context context) {
this.context = context
}
...
}
After that, you just have to provide it in your HttpRequesterModule:
#Module
public class HttpRequesterModule {
private final Context context;
public HttpRequesterModule(Context context) {
this.context = context;
}
#Provides #Singleton
HttpRequester provideHttpRequester(Context context){
return new HttpRequester(context);
}
#Provides
Context provideContext() {
return context;
}
}
Now you just have to pass a Context to your module

Related

How to notify activity when repository class gets the data?

I'm new in android architecture component. this is my code , i'm at the point that I don't know how to notify my activity and get the results back
these are my codes:
Activity:
private void iniViewModels() {
Observer<List<User>>usersObserver=new Observer<List<User>>() {
#Override
public void onChanged(#Nullable List<User> users) {
Log.v("this","LiveData: ");
for (int i=0;i<users.size();i++){
Log.v("this",users.get(i).getName());
}
}
};
mViewModel = ViewModelProviders.of(this)//of-->name of act or fragment
.get(AcActivityViewModel.class);///get -->the name of viewModelClass
mViewModel.mUsers.observe(this,usersObserver);
}
this is my viewModel Class:
public class IpStaticViewModel extends AndroidViewModel {
public LiveData<List<Ipe>> ips;
private AppRepository repository;
public IpStaticViewModel(#NonNull Application application) {
super(application);
repository=AppRepository.getInstance(application.getApplicationContext());
}
public void getIpStatics() {
repository.getStaticIps();
}
}
this is my repository class:
public class AppRepository {
private static AppRepository ourInstance ;
private Context context;
private IpStaticInterface ipInterface;
public static AppRepository getInstance(Context context) {
if (ourInstance == null) {
ourInstance=new AppRepository(context);
}
return ourInstance;
}
private AppRepository(Context context) {
this.context=context;
}
public void getStaticIps() {
ipInterface= ApiConnection.getClient().create(IpStaticInterface.class);
ipInterface.getIpes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new SingleObserver<IpStaticList>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(IpStaticList ipStaticList) {
List<Ipe>ips=ipStaticList.getIpes();
}
#Override
public void onError(Throwable e) {
Log.v("this","Eror "+ e.getMessage());
}
});
}
}
I'm using retrofit for fetching the data ,it fetch the data successfully but I don't know how to notify my activity
can you help me?
Have a MutableLiveData
final MutableLiveData<List<Ipe>> data = new MutableLiveData<>();
In onSucess
public MutableLiveData<List<Ipe>> getStaticIps() {
ipInterface= ApiConnection.getClient().create(IpStaticInterface.class);
ipInterface.getIpes()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new SingleObserver<IpStaticList>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onSuccess(IpStaticList ipStaticList) {
List<Ipe>ips=ipStaticList.getIpes();
data.setValue(ips);
}
#Override
public void onError(Throwable e) {
Log.v("this","Eror "+ e.getMessage());
}
});
return data;
}
In repository expose this to viewmodel
public LiveData<List<Ipe>> getIpStatics() {
return repository.getStaticIps();
}
In Activity you observe the livedata
IpStaticViewModel viewmodel = ViewModelProviders.of(this
.get(IpStaticViewModel.class)
viewModel.getIpStatics().observe(this, new Observer<List<Ipe>>() {
#Override
public void onChanged(#Nullable List<Ipe> ipes) {
if (ipes != null) {
// dosomething
}
}
});
If you want to generalize your response in case you have a error or something have a look at https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/vo/Resource.kt

Null Pointer Exception in Constructor Injection Dagger2 Android

I am trying to inject context in my Interactor class which is giving me a null pointer exception.
I have used the MVP pattern and I am trying to get access to the context in my non-activity class.
I am not really sure if this is the best technique used.
Module:
#Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
#Singleton
#Provides
public Context getContext() {
return this.context;
}
}
Component:
#Singleton
#Component(modules = {ContextModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
}
App
public class App extends Application {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder()
.contextModule(new ContextModule(this))
.build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements
TaskContract.IMainView {
#Inject
MainInteractor mainInteractor;
private MainPresnter mainPresnter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((App) getApplication()).getAppComponent().inject(this);
mainPresnter = new MainPresnter(this);
}
#Override
public void getRandomNumber(int rNum) {
Toast.makeText(this, "" + rNum, Toast.LENGTH_SHORT).show();
}
#Override
protected void onResume() {
super.onResume();
mainPresnter.fetchFromService();
}
}
Presenter
public class MainPresnter implements TaskContract.IMainPresenter,
TaskContract.OnTaskCompletionResult {
private TaskContract.IMainView mainView;
private MainInteractor mainInteractor;
public MainPresnter(TaskContract.IMainView mainView) {
this.mainView = mainView;
mainInteractor = new MainInteractor(this);
}
#Override
public void fetchFromService() {
mainInteractor.callService();
}
#Override
public void onSuccess(int rNum) {
mainView.getRandomNumber(rNum);
}
}
Interactor
public class MainInteractor implements TaskContract.IMainInteractor {
private static final int JOB_ID = 100 ;
private Context context;
#Inject
public MainInteractor(Context context) {
this.context = context;
}
public MainInteractor(TaskContract.OnTaskCompletionResult completionListener)
{
TaskService.setCompletionListener(completionListener);
}
#Override
public void callService() {
JobInfo jobInfo = new JobInfo.Builder(JOB_ID,
new ComponentName(context, TaskService.class))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPeriodic(10000)
.build();
JobScheduler jobScheduler = (JobScheduler)
context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(jobInfo);
}
}
Gradle
implementation 'com.google.dagger:dagger-android:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
You don't inject the Interactor within your Presenter - therefore it won't have a context.
You could probably restructure your Presenter to require the Interactor as a dependency - this would also mean you'd need to restructure how the completion listener is set.

android getting NULL error on inject DI into class

I can make DI from some class to use in application such as Retrofit, Picasso.
they can work fine when i use them on Activity but when i try to use some DI on other class i get NULL, for exmple this code work fine
public class ActivityRegister extends BaseActivities {
#Inject
GithubService githubService;
#Inject
JobManager jobManager;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
...
repositoryCall = githubService.getAllRepositories();
...
}
private void getRepositories() {
repositoryCall.enqueue(new Callback<List<GithubRepo>>() {
#Override
public void onResponse(Call<List<GithubRepo>> call, Response<List<GithubRepo>> response) {
List<GithubRepo> repoList = new ArrayList<>();
repoList.addAll(response.body());
Log.e("JOB ", "OK");
}
#Override
public void onFailure(Call<List<GithubRepo>> call, Throwable t) {
Log.e("JOB ", "NO!!");
}
});
}
for GithubService i get created instance successfull, not i'm trying to use that into GetLatestRepositories, but i get NULL, how can i define correctly that to injecting into class?
public class GetLatestRepositories extends Job {
#Inject
GithubService githubService;
private Call<List<GithubRepo>> repositoryCall;
public GetLatestRepositories() {
super(new Params(Priority.MID).requireNetwork().persist());
repositoryCall = githubService.getAllRepositories();
}
#Override
public void onAdded() {
}
#Override
public void onRun() throws Throwable {
repositoryCall.enqueue(new Callback<List<GithubRepo>>() {
#Override
public void onResponse(Call<List<GithubRepo>> call, Response<List<GithubRepo>> response) {
List<GithubRepo> repoList = new ArrayList<>();
repoList.addAll(response.body());
Log.e("JOB ", "OK");
}
#Override
public void onFailure(Call<List<GithubRepo>> call, Throwable t) {
Log.e("JOB ", "NO!!");
}
});
}
#Override
protected void onCancel(int cancelReason, #Nullable Throwable throwable) {
}
#Override
protected RetryConstraint shouldReRunOnThrowable(#NonNull Throwable throwable, int runCount, int maxRunCount) {
return null;
}
}
ActivityRegisterComponent component class:
#ActivityRegisterScope
#Component(modules = ActivityRegisterModule.class, dependencies = GithubApplicationComponent.class)
public interface ActivityRegisterComponent {
void injectActivityRegister(ActivityRegister homeActivity);
}
GithubApplicationComponent:
#GithubApplicationScope
#Component(modules = {GithubServiceModule.class, PicassoModule.class, JobManagerModule.class, ActivityModule.class})
public interface GithubApplicationComponent {
Picasso getPicasso();
GithubService getGithubService();
JobManager getJobManager();
}
Application class:
public class Alachiq extends Application {
...
public static Alachiq alachiq;
public static String packageName;
public static Resources resources;
private static Context context;
private GithubService githubService;
private Picasso picasso;
private GithubApplicationComponent component;
private JobManager jobManager;
private static Alachiq instance;
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
}
#Override
public void onCreate() {
super.onCreate();
//#formatter:off
resources = this.getResources();
context = getApplicationContext();
packageName = getPackageName();
//#formatter:on
Timber.plant(new Timber.DebugTree());
component = DaggerGithubApplicationComponent.builder()
.contextModule(new ContextModule(this))
.build();
githubService = component.getGithubService();
picasso = component.getPicasso();
jobManager = component.getJobManager();
}
public GithubApplicationComponent component() {
return component;
}
public static Alachiq get(Activity activity) {
return (Alachiq) activity.getApplication();
}
public static Alachiq getInstance() {
return instance;
}
public static Context getContext() {
return context;
}
}
and ActivityRegister onCreate:
ApplicationComponent component = DaggerApplicationComponent.builder()
.githubApplicationComponent(Alachiq.get(this).component())
.build();
GithubService class:
public interface GithubService {
#GET("users/{username}/repos")
Call<List<GithubRepo>> getReposForUser(#Path("username") String username);
#GET("repositories")
Call<List<GithubRepo>> getAllRepositories();
#GET("users/{username}")
Call<GithubUser> getUser(#Path("username") String username);
}
Before you can even use the object from GithubService class you need to do the following:
myComponent= DaggerMyComponent.builder().computerModule(new ComputerModule()).build();//replace accordingly.
In your case you will have to do something like:
githubService = DaggerGithubApplicationComponent.builder().nameofYourModule(new NameOfTheClass()).build);
Now you can use the githubService object:
repositoryCall = githubService.getAllRepositories();
This is a type of design pattern called creational.

Dagger-2 - Can't access my xml resources

Sorry for the long question / code and my english skills :)
I want to use Dagger-2 in my new android app. I have no experience with Dagger-2 or other dependency libraries. I think i misunderstand something...
Here are the relevant application. If the activity "OverviewActivity" starts it injects the "OverviewPresenter" and so on.. (OverviewActivity->OverviewPresenter->CategoriesPovider->DBOpenHelper->DBDefaults).
At the first start the class DBDefaults should prefill the database with some default values. At the time it should access the resources files i get a NPE. Can anybody tell me why this happens? I tried to use the "Log" tool to check if any needed variable is null but everything looks fine. Gets the DBDefaults class the wrong context?
Finally the method throws a NPE
context.getResources().getStringArray(R.array.category_colors);
But here is my code.
AppComponent.java
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
Context getContext();
Application getApplication();
DBOpenHelper getDBOpenHelper();
}
AppModule.java
#Module
public class AppModule {
private final Manager app;
public AppModule(Manager app) {
this.app = app;
}
#Singleton
#Provides
public Application provideApplication() {
return app;
}
#Singleton
#Provides
public Context provideContext() {
return app.getApplicationContext();
}
#Singleton
#Provides
public DBOpenHelper provideDBOpenHelper() {
return new DBOpenHelper(app);
}
}
OverviewComponent.java
#ActivityScope
#Component(dependencies = AppComponent.class)
public interface OverviewComponent {
void inject(OverviewActivity activity);
OverviewPresenter getOverviewPresenter();
}
OverviewPresenter.java
public class OverviewPresenter extends MvpBasePresenter<OverviewView> {
#Inject
public OverviewPresenter(CategoriesProvider provider) {
Log.d("OverviewPresenter", "presenter..");
}
}
CategoriesProvider.java
public class CategoriesProvider extends BaseProvider {
#Inject
public CategoriesProvider(DBOpenHelper dbOpenHelper) {
super(dbOpenHelper);
// Just testing...
dbOpenHelper.getReadableDatabase();
}
}
DBOpenHelper.java
public class DBOpenHelper extends SQLiteOpenHelper {
private static final String db = "manager";
private static final int version = 1;
private Context context;
#Inject
public DBOpenHelper(Context context) {
super(context, db, null, version);
this.context = context;
Log.d("DBOpenHelper", "database...");
if (context == null) {
Log.d("DBOpenHelper", "wtf...");
}
}
#Override
public void onCreate(SQLiteDatabase db) {
// db structure
db.execSQL(CategoriesTable.getCreateTableQuery());
db.execSQL(UsersTable.getCreateTableQuery());
// default values
DBDefaults defaults = new DBDefaults(db, context);
defaults.insertSystemUser();
defaults.insertCategories();
}
}
DBDefaults.java
public class DBDefaults {
private SQLiteDatabase db;
private Context context;
public DBDefaults(SQLiteDatabase db, Context context) {
this.db = db;
this.context = context;
if (context == null) {
Log.d("DBDefaults", "wtf... in Defaults");
}
}
public void insertCategories() {
String[] test = context.getResources().getStringArray(R.array.category_colors);
for (String item : test) {
Log.d("Categories", item);
}
// NPE ?!?!?!
}
}
EDIT
My Manger class. Here I'm storing my app component and init my AppModule
public class Manager extends Application {
private AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
My Activity
public class OverviewActivity extends MvpActivity<OverviewView, OverviewPresenter> {
public OverviewComponent overviewComponent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_navigation);
}
#Override
public void inject() {
Log.d("Activity", "inject");
overviewComponent = DaggerOverviewComponent.builder()
.appComponent(((MoneyManager)getApplication()).getAppComponent())
.build();
overviewComponent.inject(this);
}
#Override
public OverviewPresenter getPresenter() {
Log.d("Activity", "getPresenter");
return overviewComponent.getOverviewPresenter();
}
}
If CategoriesProvider is a ContentProvider, you might get null when calling Application.getApplicationContext(). So the context that you're injecting could be null. You can verify this in AppModule. Try logging the result before returning it. Note that Application.getApplicationContext() normally returns the same instance, so you could just return app; instead of what you currently have.

Dagger 2 Not injecting into dependant module

I checked all questions but did not find any clue. I stripped my problem to a simplest code:
Situation:
I want to have:
CatComponent catComponent = DaggerCatComponent.builder()
.kameModule(new KameModule(MainActivity.this))
.build();
catComponent.getCatAnalyzer().analyze();
I have created component:
#Component(modules = {KameModule.class, CatAnalyzerModule.class})
public interface CatComponent {
CatAnalyzer getCatAnalyzer();
}
And modules:
#Module
public class KameModule {
private Context context;
public KameModule(Context context) {
this.context = context;
}
#Provides
KameCat provideKameCat() {
return new KameCat(context );
}
}
#Module(includes = KameModule.class)
public class CatAnalyzerModule {
#Inject
KameCat cat;
#Provides
CatAnalyzer provideCatAnalyzer() {
return new CatAnalyzer(cat);
}
}
And classes:
public class KameCat {
Context context;
public KameCat(Context context) {
this.context = context;
}
public void doCatStuff() {
Toast.makeText(context, "Poo and Meow", Toast.LENGTH_LONG).show();
}
}
public class CatAnalyzer {
#Inject
KameCat cat;
#Inject
public CatAnalyzer(KameCat cat) {
this.cat = cat;
}
void analyze() {
cat.doCatStuff();
}
}
When I retrieve my CatAnalyzer object from CatComponent it has cat field nulled.
I have no idea why Dagger won't inject it. Could you guide me somehow?
Proper code:
#Module(includes = KameModule.class)
public class CatAnalyzerModule {
#Inject //remove this
KameCat cat;// remove this
#Provides
// Add cat as a argument and let KameModule provide it..
CatAnalyzer provideCatAnalyzer(KameCat cat) {
return new CatAnalyzer(cat);
}
}
Thanks to:
https://www.future-processing.pl/blog/dependency-injection-with-dagger-2/

Categories

Resources