子类的 Dagger 注入
Dagger injection for sublclass
我在基础 class 中有 @inject,因此所有子classes 将从基础 class 注入依赖项,然后我遇到了一个问题,它说 "You must explicitly add it to the 'injects' option in one of your modules".
将所有子class明确添加到注入选项确实解决了这个问题,但是我需要确保每当我有一个新的子class我都必须添加新的子class到"injects",否则会得到异常。有没有简单的方法来处理?
谢谢!
如果我理解正确你想调用 inject(base activity)
但你的 @Inject
注释字段在 类 子类基础 activity.
有一种基于反射的解决方案(因此它可能会破坏 ProGuard)。 blog post.
中描述了解决方案
package info.android15.dagger2example;
import java.lang.reflect.Method;
import java.util.HashMap;
public class Dagger2Helper {
private static HashMap<Class<?>, HashMap<Class<?>, Method>> methodsCache = new HashMap<>();
/**
* This method is based on https://github.com/square/mortar/blob/master/dagger2support/src/main/java/mortar/dagger2support/Dagger2.java
* file that has been released with Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ by Square, Inc.
* <p/>
* Magic method that creates a component with its dependencies set, by reflection. Relies on
* Dagger2 naming conventions.
*/
public static <T> T buildComponent(Class<T> componentClass, Object... dependencies) {
buildMethodsCache(componentClass);
String fqn = componentClass.getName();
String packageName = componentClass.getPackage().getName();
// Accounts for inner classes, ie MyApplication$Component
String simpleName = fqn.substring(packageName.length() + 1);
String generatedName = (packageName + ".Dagger" + simpleName).replace('$', '_');
try {
Class<?> generatedClass = Class.forName(generatedName);
Object builder = generatedClass.getMethod("builder").invoke(null);
for (Method method : builder.getClass().getMethods()) {
Class<?>[] params = method.getParameterTypes();
if (params.length == 1) {
Class<?> dependencyClass = params[0];
for (Object dependency : dependencies) {
if (dependencyClass.isAssignableFrom(dependency.getClass())) {
method.invoke(builder, dependency);
break;
}
}
}
}
//noinspection unchecked
return (T)builder.getClass().getMethod("build").invoke(builder);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <T> void buildMethodsCache(Class<T> componentClass) {
if (!Dagger2Helper.methodsCache.containsKey(componentClass)) {
HashMap<Class<?>, Method> methods = new HashMap<>();
for (Method method : componentClass.getMethods()) {
Class<?>[] params = method.getParameterTypes();
if (params.length == 1)
methods.put(params[0], method);
}
Dagger2Helper.methodsCache.put(componentClass, methods);
}
}
public static void inject(Class<?> componentClass, Object component, Object target) {
HashMap<Class<?>, Method> methods = methodsCache.get(componentClass);
if (methods == null)
throw new RuntimeException("Component " + componentClass + " has not been built with " + Dagger2Helper.class);
Class targetClass = target.getClass();
Method method = methods.get(targetClass);
if (method == null)
throw new RuntimeException("Method for " + targetClass + " injection does not exist in " + componentClass);
try {
method.invoke(component, target);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
然后在你的基地activity你可以这样做:
Dagger2Helper.inject(AppComponent.class, component, this);
我认为一点反射不会对性能产生太大影响,对我来说真正的问题是破坏 ProGuard。
我在基础 class 中有 @inject,因此所有子classes 将从基础 class 注入依赖项,然后我遇到了一个问题,它说 "You must explicitly add it to the 'injects' option in one of your modules".
将所有子class明确添加到注入选项确实解决了这个问题,但是我需要确保每当我有一个新的子class我都必须添加新的子class到"injects",否则会得到异常。有没有简单的方法来处理?
谢谢!
如果我理解正确你想调用 inject(base activity)
但你的 @Inject
注释字段在 类 子类基础 activity.
有一种基于反射的解决方案(因此它可能会破坏 ProGuard)。 blog post.
中描述了解决方案package info.android15.dagger2example;
import java.lang.reflect.Method;
import java.util.HashMap;
public class Dagger2Helper {
private static HashMap<Class<?>, HashMap<Class<?>, Method>> methodsCache = new HashMap<>();
/**
* This method is based on https://github.com/square/mortar/blob/master/dagger2support/src/main/java/mortar/dagger2support/Dagger2.java
* file that has been released with Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ by Square, Inc.
* <p/>
* Magic method that creates a component with its dependencies set, by reflection. Relies on
* Dagger2 naming conventions.
*/
public static <T> T buildComponent(Class<T> componentClass, Object... dependencies) {
buildMethodsCache(componentClass);
String fqn = componentClass.getName();
String packageName = componentClass.getPackage().getName();
// Accounts for inner classes, ie MyApplication$Component
String simpleName = fqn.substring(packageName.length() + 1);
String generatedName = (packageName + ".Dagger" + simpleName).replace('$', '_');
try {
Class<?> generatedClass = Class.forName(generatedName);
Object builder = generatedClass.getMethod("builder").invoke(null);
for (Method method : builder.getClass().getMethods()) {
Class<?>[] params = method.getParameterTypes();
if (params.length == 1) {
Class<?> dependencyClass = params[0];
for (Object dependency : dependencies) {
if (dependencyClass.isAssignableFrom(dependency.getClass())) {
method.invoke(builder, dependency);
break;
}
}
}
}
//noinspection unchecked
return (T)builder.getClass().getMethod("build").invoke(builder);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <T> void buildMethodsCache(Class<T> componentClass) {
if (!Dagger2Helper.methodsCache.containsKey(componentClass)) {
HashMap<Class<?>, Method> methods = new HashMap<>();
for (Method method : componentClass.getMethods()) {
Class<?>[] params = method.getParameterTypes();
if (params.length == 1)
methods.put(params[0], method);
}
Dagger2Helper.methodsCache.put(componentClass, methods);
}
}
public static void inject(Class<?> componentClass, Object component, Object target) {
HashMap<Class<?>, Method> methods = methodsCache.get(componentClass);
if (methods == null)
throw new RuntimeException("Component " + componentClass + " has not been built with " + Dagger2Helper.class);
Class targetClass = target.getClass();
Method method = methods.get(targetClass);
if (method == null)
throw new RuntimeException("Method for " + targetClass + " injection does not exist in " + componentClass);
try {
method.invoke(component, target);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
然后在你的基地activity你可以这样做:
Dagger2Helper.inject(AppComponent.class, component, this);
我认为一点反射不会对性能产生太大影响,对我来说真正的问题是破坏 ProGuard。