匕首注射为sublclass

时间:2018-02-13 20:13:32

标签: android dependency-injection subclass dagger

我在基类中有@inject,因此所有子类都会从基类中注入该依赖项,然后我遇到了一个问题,它说'#34;你必须明确地将它添加到'注入&#39 ;您的某个模块中的选项"。

明确地将所有子类添加到injects选项确实解决了问题,但是我需要确保每当我有一个新的子类时,我将不得不将新的子类添加到&#34;注入&#34;,或者将获得例外。有没有一种简单的方法来处理它?<​​/ p>

谢谢!

1 个答案:

答案 0 :(得分:1)

如果我理解正确您想要致电inject(base activity),但您的@Inject注释字段在类中对基本活动进行子类化。

有一种基于反射的解决方案(可能会打破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);
        }
    }
}

然后在你的基础活动中你可以这样做:

Dagger2Helper.inject(AppComponent.class, component, this);

我不认为一点反思会对性能造成太大影响,对我而言,真正的问题是打破ProGuard。