如何设置dependency injection使用匕首除了活动和片段?

我开始使用Dagger设置dependency injection,如下所示。 请鼓励我纠正我的实施,因为我可能在那里犯错! 该实现遵循该项目提供的android-simple示例 。 在下面,你可以看到我如何成功地为ActivitiesFragments添加dependency injection。 我试图保持现在的容易,所以我决定注入木材作为Android日志util的logging器替代。

 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); } } 

到目前为止, AndroidModule没有在任何地方使用,但是当需要ContextLayoutInflater ,例如在CursorAdapters可能会有所帮助。

 import android.content.Context; import android.view.LayoutInflater; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; /** * A module for Android-specific dependencies which require a {@link Context} * or {@link android.app.Application} to create. */ @Module(library = true) public class AndroidModule { private final ExampleApplication mApplication; public AndroidModule(ExampleApplication application) { mApplication = application; } /** * Allow the application context to be injected but require that it be * annotated with {@link ForApplication @Annotation} to explicitly * differentiate it from an activity context. */ @Provides @Singleton @ForApplication Context provideApplicationContext() { return mApplication; } @Provides @Singleton LayoutInflater provideLayoutInflater() { return (LayoutInflater) mApplication .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } } 

我不确定应用程序特定的提供程序会在这里。 我留在现在的伐木

 import dagger.Module; @Module( complete = false ) public class ExampleModule { public ExampleModule() { // TODO put your application-specific providers here! } } 

我准备LoggingModule提供访问木材

 package com.example.debugging; import javax.inject.Singleton; import dagger.Module; import dagger.Provides; import com.example.BuildConfig; import com.example.activities.BaseFragmentActivity; import com.example.activities.DetailsActivity; import com.example.fragments.BaseListFragment; import com.example.fragments.ProfilesListFragment; import timber.log.Timber; @Module(injects = { // Activities BaseFragmentActivity.class, DetailsActivity.class, // Fragments BaseListFragment.class, ProfilesListFragment.class }) public class LoggingModule { @Provides @Singleton Timber provideTimber() { return BuildConfig.DEBUG ? Timber.DEBUG : Timber.PROD; } } 

Activities的基类将自身注入到对象图中

 package com.example.activities; import android.os.Bundle; import com.actionbarsherlock.app.SherlockFragmentActivity; import javax.inject.Inject; import com.example.ExampleApplication; import timber.log.Timber; public abstract class BaseFragmentActivity extends SherlockFragmentActivity { @Inject Timber mTimber; @Override protected void onCreate(Bundle savedInstanceState) { // ... super.onCreate(savedInstanceState); ((ExampleApplication) getApplication()).inject(this); } } 

木材已经存在的任何子类效益。

 package com.example.activities; import android.os.Bundle; import com.example.R; public class DetailsActivity extends BaseFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_details); mTimber.i("onCreate"); // ... } } 

同样的Fragments :基类做肮脏的工作…

 package com.example.fragments; import android.os.Bundle; import com.actionbarsherlock.app.SherlockListFragment; import javax.inject.Inject; import com.example.ExampleApplication; import timber.log.Timber; public abstract class BaseListFragment extends SherlockListFragment { @Inject Timber mTimber; @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ((ExampleApplication) getActivity().getApplication()).inject(this); } } 

…和子类从其超级类的好处。

 package com.example.fragments; import android.os.Bundle; public class ProfilesListFragment extends BaseListFragment { @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // TODO This might be a good example to inject resources // in the base class. But how? setEmptyText(getResources() .getString(R.string.profiles_list_no_content)); mTimber.i("onActivityCreated"); // ... } } 

到现在为止还挺好。 但如何可以将木材注入BaseCursorAdapterBaseContentProviderBaseSQLiteOpenHelperBaseServiceBaseAsyncTaskstatic帮助器方法?

Christopher Perry弃用的android示例指出了如何将一个Adapter插入到ListFragment中,而不是如何将ContextResourcesLayoutInflaterCursor插入到(Cursor)Adapter或者只是Timber中


参考文献:

  • 匕首
  • android-简单的例子
  • Jesse Wilson – Dagger:Android和Java的快速dependency injection器
  • Eric Burke – Android应用程序解剖

Solutions Collecting From Web of "如何设置dependency injection使用匕首除了活动和片段?"

看看Andy Dennie在不同情况下注射的例子:

https://github.com/adennie/fb-android-dagger

我注射的一些点:

  • ActivityServiceFragment子类:在onCreate
  • BroadcastReceiver子类(包括,例如AppWidgetProvider ):在onReceive

在这个问题上有很多事情要做,但这可能是与我的一个Gist的帮助。 如果你能得到一个Context地方,你可以注入它的基础上由你的Application类维护的ObjectGraph


由JJD编辑:

Gist中的ObjectGraph可以集成如下:

 public class ExampleApplication extends Application implements ObjectGraph.ObjectGraphApplication { /* Application Lifecycle */ @Override public void onCreate() { // Creates the dependency injection object graph _object_graph = ObjectGraph.create(...); } /* ObjectGraphApplication Contract */ @Override public void inject(@Nonnull Object dependent) { _object_graph.inject(dependent); } /** Application's object graph for handling dependency injection */ private ObjectGraph _object_graph; } 

 public abstract class BaseFragmentActivity extends SherlockFragmentActivity { @Inject Timber _timber; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); ObjectGraph.inject(this); } } 

 public abstract class BaseListFragment extends SherlockListFragment { @Inject Timber _timber; @Override public void onActivityCreated(Bundle icicle) { super.onActivityCreated(icicle); ObjectGraph.inject(this); } } 

对于BaseCursorAdapterBaseContentProviderBaseService类似的工作。

我们必须做同样的事情(即到处注入logging器)。 我们最终制作了一个非常小的静态包装(因此在任何地方都可用),这个包装是通过静态注入匕首的类来包装的。

 package com.example.secret; import javax.inject.Inject; import com.example.interfaces.Logger; public class LoggerProvider { @Inject static Logger logger; public LoggerProvider() { } public static Logger getLogger() { return logger; } 

}

logging器实现您的日志logging界面。 要在应用程序级别注入,您需要:

  graph = ObjectGraph.create(getModules().toArray()); graph.injectStatics(); 

代码在这里: https : //github.com/nuria/android-examples/tree/master/dagger-logger-example

注入ContextResourcesLayoutInflater (在应用程序中新build应用程序时传递应用程序上下文)。

 @Module(complete = false) public class AndroidServicesModule { private final Context context; public AndroidServicesModule(@ForApplication Context context) { this.context = context; } @Provides @Singleton Resources provideResources() { return context.getResources(); } @Provides @Singleton LocationManager provideLocationManager() { return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); } @Provides @Singleton LayoutInflater provideLayoutInflater() { return (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Provides @Singleton Resources provideResources() { return context.getResources(); } @Provides @ForApplication Context provideContext() { return context; } } 

当然,你也许应该使用一个注释来限定上下文,指定它是应用程序上下文(例如@ForApplication )。

如果你需要相当于Roboguice的@InjectResource(int)我不能想到任何事情。 Butterknife似乎是正确的lib添加到此。 看到这里

您可以将这些结构添加到ExampleApplication类:

 private static ExampleApplication INSTANCE; @Override public void onCreate() { super.onCreate(); INSTANCE = this; mObjectGraph = ObjectGraph.create(getModules()); mObjectGraph.injectStatics(); mObjectGraph.inject(this); } public static ExampleApplication get() { return INSTANCE; } 

之后,您可以用一条简单的线条注入任何对象( this表示):

 ExampleApplication.get().inject(this) 

这应该在您为手动创build的对象的构造函数中调用,或者在由Android系统pipe理的对象上创buildonCreate (或模拟)。