我开始使用Dagger设置依赖注入,如下所示。因为我可能有错误,所以请鼓励我更正我的实施!实现遵循项目提供的android-simple example。在下文中,您可以看到我是如何为Activities
和Fragments
成功添加依赖项注入的。我现在试着保持简单,所以我决定将Timber作为Android's 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);
}
}
到目前为止AndroidModule
并未在任何地方使用,但在需要Context
和LayoutInflater
时可能会有所帮助,例如在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
,可以访问 Timber 。
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);
}
}
... Timber 已经存在的任何子类受益。
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");
// ...
}
}
到目前为止一切顺利。但是如何将 Timber 注入BaseCursorAdapter
,BaseContentProvider
,BaseSQLiteOpenHelper
,BaseService
,BaseAsyncTask
和static
辅助方法?
已弃用的android example by Christopher Perry指出如何将Adapter注入ListFragment但不注明如何注入Context
,Resources
,LayoutInflater
,Cursor
进入(Cursor)Adapter
或 Timber 。
参考文献:
答案 0 :(得分:8)
查看Andy Dennie在不同情况下注射的示例:
https://github.com/adennie/fb-android-dagger
我注入的一些要点:
Activity
,Service
和Fragment
子类:onCreate
BroadcastReceiver
子类(包括,例如AppWidgetProvider
):onReceive
答案 1 :(得分:5)
tl; dr在这个问题中有很多事情要发生,但Gist of mine可能会有所帮助。如果您可以在某个地方获得Context
,则可以根据ObjectGraph
课程维护的Application
进行注入。
按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);
}
}
BaseCursorAdapter
,BaseContentProvider
和BaseService
的类似作品。
答案 2 :(得分:2)
我们必须做同样的事情(即在任何地方注入记录器)。我们最终创建了一个非常小的静态包装器(因此可以在任何地方使用),它包含一个静态注入匕首的类。
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;
}
}
Logger实现您的日志记录界面。要在应用程序级别注入它,您需要:
graph = ObjectGraph.create(getModules().toArray());
graph.injectStatics();
此处代码:https://github.com/nuria/android-examples/tree/master/dagger-logger-example
答案 3 :(得分:2)
注入Context
,Resources
和LayoutInflater
(在应用程序中重新启动时传递应用程序上下文)。
@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;
}
}
当然你应该qualify带有注释的上下文指定它是应用程序上下文(例如@ForApplication
)。
如果你需要相当于Roboguice的@InjectResource(int)
我无法想到任何事情。 Butterknife似乎是正确的lib添加它。见here
答案 4 :(得分:0)
您可以将这些构造添加到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)
这应该在您手动创建的对象的构造函数中调用,或者对于由Android系统管理的对象调用onCreate
(或模拟)。