匕首和对提供的类的依赖

时间:2013-02-13 04:05:36

标签: android dependency-injection dagger

我是" Daggering"我的Android应用程序和我面临一个小问题,我不知道它是我或框架的错。如果是我,我会对自己感到非常失望:)。

我有以下课程提供:

@Singleton
public class XmlService {

    private final DataCommitter<XmlWritable> mXmlCommitter;
    private final DataReader<XmlPushable> mXmlReader;
    private final ConcurrentObjectMonitor mConcObjMonitor;

   @Inject
   public XmlService(DataCommitter<XmlWritable> xmlCommitter,
        DataReader<XmlPushable> xmlProvider,
        ConcurrentObjectMonitor concObjMonitor) {
    mXmlCommitter = xmlCommitter;
    mXmlReader = xmlProvider;
    mConcObjMonitor = concObjMonitor;
   }

使用以下(以及其他)类:

public class XmlDataReader implements DataReader<XmlPushable> {
  // No Singleton no more.
  // Eager Singleton (Therefore it should be made thread safe)
  //static XmlDataReader mInstance = new XmlDataReader();
  [CUT]

  protected XmlPullParser mXmlPullParser;

  @Inject
  public void XmlDataRead(XmlPullParser xmlPullParser) {
      mXmlPullParser = xmlPullParser;
  }

这个类在我的XmlServiceModule中引用如下:

@Module(complete = true)
public class XmlServiceModule {

    @Provides DataReader<XmlPushable> provideDataReader(XmlDataReader dataReader) {
        return dataReader;
    }
}

现在,问题是,注入提供的课程是否合法?因为我在XmlDataReader ctor上遇到@Inject错误:无法注入public void XmlDataRead(org.xmlpull.v1.XmlPullParser)。


编辑:抱歉,伙计们,我的示例代码中有错误,但我会保留原样,因为它有助于理解下面的克里斯蒂安答案。

1 个答案:

答案 0 :(得分:3)

实际上,您的示例代码中存在错误。您没有可注入的构造函数 - 您不能注入实例方法,只能注入构造函数,并且永远不会调用该方法。

你应该:

public class XmlDataReader implements DataReader<XmlPushable> {

  protected final XmlPullParser mXmlPullParser;

  @Inject
  public XmlDataReader(XmlPullParser xmlPullParser) {
      mXmlPullParser = xmlPullParser;
  }
}

这样它就是一个构造函数,并且会被正确地注入。

至于整体方法,你的方向是正确的。您@Provide DataReader<XmlPushable,并在您的提供方法中有效地将XmlDataReader绑定到它。到现在为止还挺好。当被要求DataReader<XmlPushable>时,Dagger将使用该绑定,并将有效地传递依赖关系,并提供XmlDataReader来满足此要求。

XmlDataReader有一个@Inject带注释的构造函数,因此Dagger的分析会将其视为“可注入类型”,因此您不需要@Provides来提供它。只要你有XmlPullParser要么有@Inject带注释的构造函数,要么在模块的@Provides方法中提供,那么你在这里编写的代码看起来不错,但不是非常完整。

您的@Module中没有列出任何entryPoints,并且 必须 有一个类,它将是您从ObjectGraph获得的第一个类。所以这段代码尽可能合理,但不完整。你需要注入的东西(通过字段或构造函数)DataReader<XmlPushable>例如,你可以创建一个FooActivity来执行此操作。

考虑:

public class XmlDataReader implements DataReader<XmlPushable> {    
  protected XmlPullParser mXmlPullParser;

  @Inject public XmlDataReader(XmlPullParser xmlPullParser) {
    mXmlPullParser = xmlPullParser;
  }
}

@Module(entryPoints = { FooActivity.class, BarActivity.class })
public class XmlServiceModule {
  @Provides DataReader<XmlPushable> provideDataReader(XmlDataReader dataReader) {
    return dataReader;
  }

  @Singleton
  @Provides XmlPullParserFactory parserFactory() {
     XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
     factory.setNamespaceAware(true);
     return factory;
  }

  @Provides XmlPullParser parser(XmlPullParserFactory factory) {
     XmlPullParser xpp = factory.newPullParser();
  }
}

public class YourApp extends Application {
  private ObjectGraph graph;

  @Override public void onCreate() {
    super.onCreate();
    graph = ObjectGraph.get(new ExampleModule(this));
  }

  public ObjectGraph graph() {
    return objectGraph;
  }
}

public abstract class BaseActivity extends Activity {
  @Override protected void onCreate(Bundle state) {
    super.onCreate(state);
    ((YourApp) getApplication()).objectGraph().inject(this);
  }
}

class FooActivity extends BaseActivity {
  @Inject DataReader<XmlPushable> reader;

  @Override public void onCreate(Bundle bundle) {
    super.onCreate(bundle);
    // custom Foo setup
  }
}

class BarActivity extends BaseActivity {
  @Inject DataReader<XmlPushable> reader;

  @Override public void onCreate(Bundle bundle) {
    super.onCreate(bundle);
    // custom Bar setup
  }
}

这可能接近你想要的。所有东西都可以从入口点到达,所有你依赖的东西都是绑定的。这两个活动是您的“入口点”(对象图中的根)。初始化后,他们最终会自行调用ObjectGraph的{​​{1}}方法,这会导致Dagger注入任何inject(Object)个带注释的字段。这些字段是@Inject字段,它由XmlDataReader满足,XmlDataReader由XmlPullParser提供,XmlPullParser是使用XmlPullParser提供的。这一切都沿着依赖链流动。

小注 - DataReader<XmlPushable>是默认值。您不需要指定完整,除非它不完整并指定@Module(complete=true)