所以,我正在重新设计我的Android应用程序以使用Dagger.我的应用程序庞大而复杂,我最近遇到了以下情况:
对象A需要一个特殊的DebugLogger实例,这是一个完美的注入候选者.我可以通过A的构造函数注入它,而不是绕过记录器.这看起来像这样:
class A
{
private DebugLogger logger;
@Inject
public A(DebugLogger logger)
{
this.logger = logger;
}
// Additional methods of A follow, etc.
}
Run Code Online (Sandbox Code Playgroud)
到目前为止这是有道理的.但是,A需要由另一个类B构造.必须构造A的多个实例,所以遵循Dagger的做事方式,我简单地将一个注入Provider<A>到B中:
class B
{
private Provider<A> aFactory;
@Inject
public B(Provider<A> aFactory)
{
this.aFactory = aFactory;
}
}
Run Code Online (Sandbox Code Playgroud)
好的,到目前为止还不错.但等等,突然A需要额外的输入,例如一个称为"数量"的整数,这对于它的构造至关重要.现在,我的A构造函数需要如下所示:
@Inject
public A(DebugLogger logger, int amount)
{
...
}
Run Code Online (Sandbox Code Playgroud)
突然,这个新参数干扰了注射.而且,即使这确实有效,除非我弄错了,否则在从提供者检索新实例时我无法传递"金额".我可以在这里做几件事,我的问题是哪一个是最好的?
我可以通过添加一个setAmount()预期在构造函数之后调用的方法来重构A. 然而,这是丑陋的,因为它迫使我延迟A的构造直到"数量"被填入.如果我有两个这样的参数,"数量"和"频率",那么我将有两个安装者,这将意味着要么复杂的检查以确保在调用两个setter之后恢复A的构造,或者我将不得不在混合中添加第三个方法,如下所示:
(Somewhere in B):
A inst = aFactory.get();
inst.setAmount(5);
inst.setFrequency(7);
inst.doConstructionThatRequiresAmountAndFrequency();
Run Code Online (Sandbox Code Playgroud)
另一种选择是我不使用基于构造函数的注射并使用基于场的注射.但现在,我必须把我的田地公之于众.这对我来说并不合适,因为现在我有义务将我班级的内部数据透露给其他班级.
到目前为止,我能想到的唯一优雅的解决方案是为提供者使用基于字段的注入,如下所示:
class A
{
@Inject
public Provider<DebugLogger> loggerProvider; …Run Code Online (Sandbox Code Playgroud) 我开始使用Dagger设置依赖注入,如下所示.因为我可能有错误,所以请鼓励我更正我的实施!该实现遵循项目提供的android-simple示例.在下面你可以看到我是如何成功添加依赖注入Activities和Fragments.我现在试着保持简单,所以我决定将Timber注入Android的log util的记录器替换.
import android.app.Application;
import java.util.Arrays;
import java.util.List;
import dagger.ObjectGraph;
import com.example.debugging.LoggingModule;
public class ExampleApplication extends Application {
private ObjectGraph mObjectGraph;
protected List<Object> getModules() {
return Arrays.asList(
new AndroidModule(this),
new ExampleModule(),
new LoggingModule()
);
}
private void createObjectGraphIfNeeded() {
if (mObjectGraph == null) {
Object[] modules = getModules().toArray();
mObjectGraph = ObjectGraph.create(modules);
}
}
public void inject(Object object) {
createObjectGraphIfNeeded();
mObjectGraph.inject(object);
}
}
Run Code Online (Sandbox Code Playgroud)
到现在AndroidModule没有任何地方使用,但可能会有所帮助时,Context并LayoutInflater …
android dependency-injection android-contentprovider android-asynctask dagger
从Kotling 1.3.21更新到1.3.30后生成错误:
AppComponent.java:16: error: [Dagger/MissingBinding]
java.util.Map<java.lang.Class<? extends androidx.lifecycle.ViewModel>,
javax.inject.Provider<androidx.lifecycle.ViewModel>>
cannot be provided without an @Provides-annotated method.
Run Code Online (Sandbox Code Playgroud)
在两个对Kotlin,Dagger和Architecture组件具有相似依赖性的不同项目上进行了复制。
我怀疑它与kotlin 1.3.30中的最近kapt更新有关:https ://blog.jetbrains.com/kotlin/2019/04/kotlin-1-3-30-released/
试图禁用/启用文章中的kapt选项,尝试了gradle clean,使缓存无效,没有任何帮助。只有降级到1.3.21项目才能成功构建。
我想让Dagger在我的项目上工作.
但是,在编译期间,我在其中一个类上遇到以下异常:
错误:Foo上没有可注射成员.你想添加一个注射构造函数吗?
但是,该类没有依赖关系,因此使用默认的no-arg构造函数:
public class Foo
{
...
}
Run Code Online (Sandbox Code Playgroud)
我是否真的需要添加一个像下面这样的可注射无参数构造函数?
public class Foo
{
@Inject
public Foo()
{
}
....
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试将应用程序Context注入其他两个对象,一个AuthManager和一个ApiClient.
它们都取决于所述的背景,并且ApiClient取决于AuthManager.为什么这是一个依赖循环,如果Context没有引用其他2?这可以解决吗?
编辑:这是一些代码
@Module
public class AppModule {
private final Application application;
public AppModule(Application application) {
this.application = application;
}
@Provides @Singleton
Context provideApplicationContext() {
return this.application;
}
}
@Module
public class NetworkModule {
@Provides @Singleton
public AuthManager providesAuthManager(AuthManager manager) {
return manager;
}
@Provides @Singleton
public ApiClient providesApiClient(ApiClientFactory factory) {
return factory.create();
}
}
@Singleton
@Component(modules = {AppModule.class, NetworkModule.class})
public interface ApplicationComponent {
void inject(BaseActivity activity); …Run Code Online (Sandbox Code Playgroud) 鉴于以下课程
abstract class AbstractClass {
@Inject SomeDependency someDependency;
}
class SomeClass extends AbstractClass {
@Inject AnotherDependency anotherDepenency;
public void onCreate() {
component = // Get component instance somehow
component.inject(this);
}
}
Run Code Online (Sandbox Code Playgroud)
在Dagger 2中,当将依赖项注入到从包含依赖项的抽象基类扩展的类中时,Dagger Generating a MembersInjector for AbstractClass. Prefer to run the dagger processor over that class instead.在编译期间显示了该类型的警告.
但是,如果我重写/实现onCreate()中AbstractClass并调用依赖注入有,也依赖someDependency将被注入这两次可能会导致意外的行为.一旦onCreate()中AbstractClass和一次onCreate()的SomeClass.
在防止重复注入依赖项的同时摆脱此警告的最佳解决方案是什么?
我将项目迁移到AndroidX,在构建项目时遇到了这些错误:
[TAG] Failed to resolve variable '${project.groupId}'
[TAG] Failed to resolve variable '${project.version}'
[TAG] Failed to resolve variable '${project.groupId}'
[TAG] Failed to resolve variable '${project.version}'
[TAG] Failed to resolve variable '${project.groupId}'
[TAG] Failed to resolve variable '${project.version}'
Run Code Online (Sandbox Code Playgroud)
我已经尝试了几种可能的解决方
enableJetifierfalse--refresh-dependencies编译器设置选项这是我的项目gradle文件:
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
google()
maven {
url 'https://maven.fabric.io/public'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.google.gms:google-services:4.0.0'
classpath 'io.fabric.tools:gradle:1.25.4'
}
}
allprojects { …Run Code Online (Sandbox Code Playgroud) 我正在尝试在Espresso仪器测试中设置Dagger,以模拟对外部资源的调用(在这种情况下为RESTful服务).我在Robolectric中为我的单元测试所遵循的模式是扩展我的生产Application类并使用将返回模拟的测试模块覆盖Dagger模块.我试图在这里做同样的事情,但是当我尝试将应用程序转换为我的自定义应用程序时,我在Espresso测试中遇到了ClassCastException.
这是我到目前为止的设置:
生产
在app/src/main/java/com/mypackage/injection下我有:
MyCustomApplication
package com.mypackage.injection;
import android.app.Application;
import java.util.ArrayList;
import java.util.List;
import dagger.ObjectGraph;
public class MyCustomApplication extends Application {
protected ObjectGraph graph;
@Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(getModules().toArray());
}
protected List<Object> getModules() {
List<Object> modules = new ArrayList<Object>();
modules.add(new AndroidModule(this));
modules.add(new RemoteResourcesModule(this));
modules.add(new MyCustomModule());
return modules;
}
public void inject(Object object) {
graph.inject(object);
}
}
Run Code Online (Sandbox Code Playgroud)
我用以下方式使用:
BaseActivity
package com.mypackage.injection.views;
import android.app.Activity;
import android.os.Bundle;
import com.mypackage.injection.MyCustomApplication;
public abstract class MyCustomBaseActivity extends Activity {
@Override
protected void …Run Code Online (Sandbox Code Playgroud) 我想知道Dagger是否有办法知道它应该在新数据可用时重新创建一个对象.
我所说的实例是我用于改造的请求标题.在某些时候(当用户登录时),我得到一个令牌,我需要将其添加到改造的标题中以进行经过身份验证的请求.问题是,我留下了相同的未经验证的改造版本.这是我的注射代码:
@Provides
@Singleton
OkHttpClient provideOkHttpClient(Cache cache) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.cache(cache).build();
client
.newBuilder()
.addInterceptor(
chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.addHeader("Accept", "Application/JSON");
Request request = requestBuilder.build();
return chain.proceed(request);
}).build();
return client;
}
@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxErrorHandlingCallAdapterFactory.create())
.baseUrl(mBaseUrl)
.client(okHttpClient)
.build();
return retrofit;
}
@Provides
@Singleton
public NetworkService providesNetworkService(Retrofit retrofit) {
return retrofit.create(NetworkService.class);
}
Run Code Online (Sandbox Code Playgroud)
关于如何使这项工作的任何想法?
我正在尝试在我的Java项目上运行Dagger 2和Lombok.当然,龙目岛必须首先运行,但实际上它是否真的有机会.起初我怀疑我可以通过类路径中库jar的相应位置来指定顺序,但是该顺序显然会被忽略.
有没有办法指定它们以某种方式运行的顺序,或者我只是不得不忍受不能组合两个AP?
我制作了一个SSCCE测试用例.
一个简单的git clone&mvn compile足以证明这个问题 - 如果您在App.java中注释第18行并取消注释第20-21行,它将进行编译,即使第18行中的Lombok表示法创建了相同的构造函数.问题是龙目岛似乎追随Dagger.