Am trying to implement dependency injection with Dagger 2, the component is initialised at base level in the application class but the app freezes on launch, right on the line of code where am initialising the dagger component, below is my code.
The application class
public class BaseApplication extends Application {
private Context context;
private Application application;
private static BaseApplication baseApplication;
protected AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
this.context = getApplicationContext();
this.application = this;
appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this)).build();
appComponent.inject(this);
//initializedApp();
}
public Context getContext() {
return context;
}
public Application getApplication() {
return application;
}
public AppComponent getAppComponent(){
return appComponent;
}
}
The AppComponent class
#Singleton
#Component(modules = {NetModule.class, AppModule.class})
public interface AppComponent {
void inject(BaseApplication baseApplication);
}
The NetModule class
#Module
public class NetModule {
#Provides
#Singleton
Retrofit provideRetrofit(){
return RetrofitClient.getInstance().getRetrofit();
}
}
The AppModule class
#Module
public class AppModule {
private Application application;
public AppModule(Application application){
this.application = application;
}
#Singleton
#Provides
Application provideApplication(){
return this.application;
}
}
Gradle dependency configuration for Dagger 2
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-android-processor:$daggerVersion"
implementation "com.google.dagger:dagger:$daggerVersion"
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
The daggerVersion being 2.23.
With this setup, the application starts but freezing with white screen, logs show that the program never runs beyond the appComponent initialisation in the BaseApplication even without injecting Retrofit anywhere in other classes. Can some body please help me figure this out, am basic to Dagger, I appreciate.
For more clarity this is my RetrofitClient class
public class RetrofitClient {
private final String TAG = RetrofitClient.class.getSimpleName();
private static String BASE_URL = "";
static {
if(BuildConfig.DEBUG){
BASE_URL = "http://0.0.0.0/api/v3/";
}else{
}
}
private static RetrofitClient mInstance;
private Retrofit retrofit;
private RetrofitClient() {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(getOkHttpClient().build())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
public static synchronized RetrofitClient getInstance() {
if (mInstance == null) {
mInstance = new RetrofitClient();
}
return mInstance;
}
public Retrofit getRetrofit() {
return retrofit;
}
private OkHttpClient.Builder getOkHttpClient(){
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.authenticator(new Authenticator());
if(BuildConfig.DEBUG){
loggingInterceptor.level(HttpLoggingInterceptor.Level.BODY);
builder.addNetworkInterceptor(loggingInterceptor);
}
return builder;
}
private HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(#NotNull String s) {
Log.d(TAG, s);
}
});
}
Related
I saw a method of using #inject annotation with parameter constructor. I found no use in #module in all parts of the project. I don't understand how this code injects or provides parameters in the constructor.
Can you help me analyze it?
Where is the datamanager provided?
In the whole project, #module + #provide is not used to provide datamanager. I only know that #inject can only annotate the parameterless constructor. I don't know where to instantiate the parameterless datamanager object. Thank you for your help
application:
public class Scallop extends Application {
private ApplicationComponent applicationComponent;
#Override
public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
}
public ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}
application module:
#Module
public class ApplicationModule {
private Scallop application;
public ApplicationModule(Scallop application) { // 提供类的构造器,传入Applicaton
this.application = application;
}
#Provides
#Singleton
Application provideApplication() {
return application;
}
#Provides
#ApplicationContext
Context provideContext() {
return application;
}
#Provides
#Singleton
Retrofit provideRetrofit() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit;
}
#Provides
#Singleton
GankIOService provideGankIOService(Retrofit retrofit) {
return retrofit.create(GankIOService.class);
}
}
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Application getApplication();
DataManager getDataManager();
}
```
one class:
#Singleton
public class DataManager {
private GankIOService gankIOService;
private PreferencesHelper preferencesHelper;
#Inject
public DataManager(GankIOService gankIOService, PreferencesHelper preferencesHelper) {
this.gankIOService = gankIOService;
this.preferencesHelper = preferencesHelper;
}
}
fragment module:
#FragmentScope
#Component(modules = FragmentModule.class, dependencies = ApplicationComponent.class)
public interface FragmentComponent {
void inject(HomeFragment homeFragment);
void inject(GanHuoPageFragment pageFragment);
void inject(XianDuFragment xianDuFragment);
void inject(XianDuPageFragment xianDuPageFragment);
void inject(PicturesFragment picturesFragment);
void inject(MoreFragment moreFragment);
}
#FragmentScope
#Documented
#Scope
#Retention(value = RetentionPolicy.RUNTIME)
public #interface FragmentScope {
}
```
here Can't understand constructor with parameter is #inject
public class GanHuoPagePresenter extends BasePresenter<GanHuoPageContract.View>
implements GanHuoPageContract.Presenter {
private DataManager dataManager;
private Disposable disposable;
#Inject
public GanHuoPagePresenter(DataManager dataManager) { // here here
this.dataManager = dataManager;
}
#Override
public void detachView() {
super.detachView();
if (disposable != null) {
disposable.dispose();
}
}
#Override
public void getGanHuo(String category, final int page) {
final List<GanHuo> ganHuoList = new ArrayList<>();
Observable<BaseResponse<GanHuo>> observable = dataManager.getGanHuo(category, page);
disposable = observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.concatMap(new Function<BaseResponse<GanHuo>, ObservableSource<GanHuo>>() {
#Override
public ObservableSource<GanHuo> apply(#NonNull BaseResponse<GanHuo> ganHuoBaseResponse)
throws Exception {
return Observable.fromIterable(ganHuoBaseResponse.getResults());
}
}).filter(new Predicate<GanHuo>() {
#Override
public boolean test(#NonNull GanHuo ganHuo) throws Exception {
return !ganHuo.getType().equals("福利");
}
}).subscribe(new Consumer<GanHuo>() {
#Override
public void accept(GanHuo ganHuo) throws Exception {
ganHuoList.add(ganHuo);
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
getView().showError(throwable.getMessage());
}
}, new Action() {
#Override`enter code here`
public void run() throws Exception {
getView().showList(ganHuoList, page);
}
});
}
}
This is how it is used in V in MVP mode:
#Inject GanHuoPagePresenter presenter
That's constructor injection. By marking a constructor with #Inject Dagger knows about the object and can create it when needed. There's no need for modules, e.g. the following is a valid Dagger setup to create some Foo.
public class Foo {
#Inject
public Foo() {}
}
#Component
interface MyComponent {
Foo getFoo();
}
That's not true that #Inject can only annotate the parameterless constructor. From documentation
Injectable constructors are annotated with #Inject and accept zero or more dependencies as arguments.
I found "your" project on Github so let's see where dependencies for GanHuoPagePresenter come from.
#Inject
public GanHuoPagePresenter(DataManager dataManager) {
this.dataManager = dataManager;
}
#Inject
public DataManager(GankIOService gankIOService,PreferencesHelper preferencesHelper){
// gankIOService is provided by ApplicationModule and preferencesHelper uses constructor injection
this.gankIOService = gankIOService;
this.preferencesHelper = preferencesHelper;
}
#Inject
public PreferencesHelper(#ApplicationContext Context context){
// context is provided again by ApplicationModule
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
}
How do I add a Subcomponent to a Module with an argument constructor?
Adding code here in addition to providing a github link:
ExampleApplication.java
public class ExampleApplication extends DaggerApplication {
#Inject
Database database;
#Override
public void onCreate() {
super.onCreate();
Timber.plant(new Timber.DebugTree());
Timber.i(database.name());
}
#Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerApplicationComponent
.builder()
.application(this)
.build();
}
}
ApplicationComponent.java
#ApplicationScope
#Component(modules = {
ApplicationModule.class,
AndroidSupportInjectionModule.class,
ActivityBindingModule.class,
DatabaseModule.class,
})
public interface ApplicationComponent extends AndroidInjector<ExampleApplication> {
Database database();
#Component.Builder
interface Builder {
#BindsInstance
Builder application(Application application);
ApplicationComponent build();
}
#Override
void inject(ExampleApplication instance);
}
DatabaseModule.java
#Module(subcomponents = DatabaseComponent.class)
public class DatabaseModule {
#Provides
#ApplicationScope
Database provideDatabase(
#NumberOfCores int numberOfCores,
DatabaseComponent.Builder databaseComponentBuilder) {
return databaseComponentBuilder
.databaseImplModule(new DatabaseImplModule(numberOfCores / 2))
.build()
.database();
}
}
DatabaseComponent.java
#Subcomponent(modules = DatabaseImplModule.class)
public interface DatabaseComponent {
// #PrivateToDatabase <- Is this a qualifier? A scope? Neither?
Database database();
#Subcomponent.Builder
interface Builder {
Builder databaseImplModule(DatabaseImplModule databaseImplModule);
DatabaseComponent build();
}
}
DatabaseImplModule.java
#Module
public class DatabaseImplModule {
DatabaseImplModule(int concurrencyLevel) {}
#Provides DatabaseConnectionPool provideDatabaseConnectionPool() {
return new DatabaseConnectionPool();
}
#Provides DatabaseSchema provideDatabaseSchema() {
return new DatabaseSchema();
}
}
Database.java
public class Database {
#Inject
public Database() { }
public String name() {
return "I have a name";
}
}
I tried to take a look at the dagger subcomponents documentation, specifically the section Subcomponents for encapsulation. I tried to create a code example
to see if I could make it work, but with no luck. Am I missing something in the documentation? (There is a line of code commented out the #PrivateToDatabase which I am not sure what kind of annotation it is).
I have a chain of Features. I would like to bind some beans inside ConfigFeature and then get them inside the MongoDBFeature. What methods should I use for that?
public final class IoCBinder extends AbstractBinder {
#Override
protected void configure() {
ConfigFeature.configureIoC(this);
MongoDBFeature.configureIoC(this);
}
}
Put some bean here:
public class ConfigFeature {
public static void configureIoC(AbstractBinder binder) {
// ....
binder.bind(configProvider).to(ConfigurationProvider.class).in(Singleton.class).named("configProvider");
}
}
And I would like to get configProvider bean here:
public class MongoDBFeature {
public static void configureIoC(AbstractBinder binder) {
// ?? get configProvider here ??
}
}
You can bind your bean to the ServiceLocator as shown in below example.
Service
public class TestService{
}
Binder
public static TestBinder extends AbstractBinder{
#Override
protected void configure() {
bind(new TestService()).to(TestService.class);
}
}
Feature 1
public class Feature1 implements Feature{
#Inject
private ServiceLocator locator;
#Override
public boolean configure(FeatureContext context) {
org.glassfish.hk2.utilities.ServiceLocatorUtilities.bind(locator,new TestBinder());
return true;
}
}
Note that a ServiceLocator instance is injected to Feature1 and the binder is bound to this locator instance.
Feature 2
public class Feature2 implements Feature{
#Inject
private TestService testService;
#Override
public boolean configure(FeatureContext context) {
return true;
}
}
Application/ResourceConfig class
public class TestConfig extends ResourceConfig {
register(Feature1.class);
// Need to make sure Feature1 is registered before Feature2.
// Another option is to register Feature2 in configure() method of Feature1 class.
register(Feature2.class);
}
I am having a hard time figuring out how to inject CachedRithms into my RithmioManager and CachedKamms into my KamilManager?
I have the following files:
AppScopeModule:
#Module
(
library = true,
complete = false,
injects = {
KamilApplication.class,
KamilManager.class
}
)
public class AppScopeModule {
/* package */ static Context sApplicationContext = null;
private final Context mApplicationContext;
AppScopeModule(Context applicationContext) {
KamilManager.initInstance(applicationContext);
mApplicationContext = applicationContext;
}
#Provides
#Singleton
KamilManager provideKamilManager() {
return KamilManager.getInstance();
}
}
KamilApplication:
public class KamilApplication extends Application implements Injector {
private ObjectGraph mObjectGraph;
#Inject
KamilManager KamilManager;
#Override
public void onCreate() {
super.onCreate();
AppScopeModule sharedAppModule = new AppScopeModule(this);
// bootstrap. So that it allows no-arg constructor in AppScopeModule
sharedAppModule.sApplicationContext = this.getApplicationContext();
List<Object> modules = new ArrayList<Object>();
modules.add(sharedAppModule);
modules.add(new AuthModule());
modules.addAll(getAppModules());
mObjectGraph = ObjectGraph.create(modules.toArray());
mObjectGraph.inject(this);
}
}
KamilManager
public class KamilManager {
#Inject
CachedKamms mCachedKamms;
private static KamilManager instance;
private boolean mWearIsConnectedToMobile;
private KamilManager() {
Log.d(TAG, "KamilManager private constructor");
}
public static void initInstance(Context appContext) {
if (instance == null) {
instance = new KamilManager();
.....doing more things here...
}
}
public static KamilManager getInstance() {
return instance;
}
}
But mCAchedKamms is always blank when I initialize the app. Any idea what I'm doing wrong?
You need to call ObjectGraph.inject(this) somewhere in KamilManager.
I suggest you to add this code to your KamilApplication class:
public ObjectGraph getObjectGraph() {
return mObjectGraph;
}
After that you need to somehow get instance of KamilApplication(pass it via constructor maybe?) in KamilManager and call:
kamilApplication.getObjectGraph.inject(this);
after this call every field in class KamilManager annotated with #Inject should be injected.
OR
Just annotate constructor of CachedKamms with #Inject
Extra:
Avoid of using library = true and complete = false unless you know what are you doing. With this settings you disable some validations at compile time.
I have a problem with #IocProvider (), annotation does not work.
The code is very similar to https://docs.jboss.org/author/display/ERRAI/Container+Wiring
public interface Test {
String getGreeting();
}
#ApplicationScoped
public class TestImpl implements Test {
public String getGreeting() {
return "Hello:)";
}
}
#IOCProvider
#Singleton
public class TestProvider implements Provider<Test> {
#Override
public Test get() {
return new TestImpl();
}
}
Then I want use DI in my broadcast service (errai-bus).
#Service
public class BroadcastService implements MessageCallback {
#Inject
Test test;
#Inject
MessageBus bus;
#Inject
public BroadcastService(MessageBus bus) {
this.bus = bus;
}
public void callback(Message message) {
MessageBuilder.createMessage()
.toSubject("BroadcastReceiver")
.with("BroadcastText", test.getGreeting()).errorsHandledBy(new ErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
return true;
}
}).sendNowWith(bus);
}
}
I get a error:
1) No implementation for com.gwtplatform.samples.basic.server.Test was bound.
while locating com.gwtplatform.samples.basic.server.Test
for field at com.gwtplatform.samples.basic.server.BroadcastService.test(BroadcastService.java:32)
at org.jboss.errai.bus.server.service.ServiceProcessor$1.configure(ServiceProcessor.java:118)
If I change the code to
#Inject
TestImpl test;
It works, but I need the provider. Do you have some idea?
Because you're trying to use #IOCProvider in server-side code. Errai IOC is completely client-side.