Daggerの使用方法私のAndroidプロジェクトで動作するようにDaggerを構成する方法?
AndroidプロジェクトでDaggerを使用したいのですが、わかりにくいです。
編集:Dagger2も2015年4月15日からリリースされており、さらに混乱しています!
[この質問は "スタブ"であり、Dagger1についてさらに学び、Dagger2についてさらに学びながら、答えに追加しています。この質問は、「質問」ではなく、ガイドです。]
Dagger 2.x(改訂版6)のガイド:
手順は次のとおりです。
1.)Dagger
を_build.gradle
_ファイルに追加します。
。
_// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.Android.tools.build:gradle:2.2.0'
classpath 'com.neenbedankt.gradle.plugins:Android-apt:1.8' //added apt for source code generation
}
}
allprojects {
repositories {
jcenter()
}
}
_
。
_apply plugin: 'com.Android.application'
apply plugin: 'com.neenbedankt.Android-apt' //needed for source code generation
Android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "your.app.id"
minSdkVersion 14
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.Android.support:appcompat-v7:24.2.1'
compile 'com.google.dagger:dagger:2.7' //dagger itself
provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
}
_
2.)依存関係を提供するAppContextModule
クラスを作成します。
_@Module //a module could also include other modules
public class AppContextModule {
private final CustomApplication application;
public AppContextModule(CustomApplication application) {
this.application = application;
}
@Provides
public CustomApplication application() {
return this.application;
}
@Provides
public Context applicationContext() {
return this.application;
}
@Provides
public LocationManager locationService(Context context) {
return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
}
_
3.)注入可能なクラスを取得するためのインターフェースを提供するAppContextComponent
クラスを作成します。
_public interface AppContextComponent {
CustomApplication application(); //provision method
Context applicationContext(); //provision method
LocationManager locationManager(); //provision method
}
_
3.1.)これは、実装を使用してモジュールを作成する方法です。
_@Module //this is to show that you can include modules to one another
public class AnotherModule {
@Provides
@Singleton
public AnotherClass anotherClass() {
return new AnotherClassImpl();
}
}
@Module(includes=AnotherModule.class) //this is to show that you can include modules to one another
public class OtherModule {
@Provides
@Singleton
public OtherClass otherClass(AnotherClass anotherClass) {
return new OtherClassImpl(anotherClass);
}
}
public interface AnotherComponent {
AnotherClass anotherClass();
}
public interface OtherComponent extends AnotherComponent {
OtherClass otherClass();
}
@Component(modules={OtherModule.class})
@Singleton
public interface ApplicationComponent extends OtherComponent {
void inject(MainActivity mainActivity);
}
_
注意::モジュールの_@Scope
_に_@Singleton
_注釈(_@ActivityScope
_または_@Provides
_など)を指定する必要がありますアノテーション付きメソッドを使用して、生成されたコンポーネント内でスコーププロバイダーを取得します。そうしないと、スコープが限定され、注入するたびに新しいインスタンスが取得されます。
3.2.)注入できるものを指定するアプリケーションスコープのコンポーネントを作成します(これはDagger 1.xの_injects={MainActivity.class}
_と同じです)。
_@Singleton
@Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope
public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods
void inject(MainActivity mainActivity);
}
_
3.3.)can自分でコンストラクタを介して作成し、_@Module
_を使用して再定義したくない依存関係の場合(forたとえば、代わりにビルドフレーバーを使用して実装のタイプを変更します)、_@Inject
_注釈付きコンストラクターを使用できます。
_public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
_
また、_@Inject
_コンストラクターを使用する場合、component.inject(this)
を明示的に呼び出す必要なく、フィールドインジェクションを使用できます。
_public class Something {
@Inject
OtherThing otherThing;
@Inject
public Something() {
}
}
_
これらの_@Inject
_コンストラクタークラスは、モジュールで明示的に指定することなく、同じスコープのコンポーネントに自動的に追加されます。
_@Singleton
_スコープの_@Inject
_コンストラクタークラスは、_@Singleton
_スコープのコンポーネントに表示されます。
_@Singleton // scoping
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
_
3.4.)次のように、特定のインターフェイスの特定の実装を定義した後:
_public interface Something {
void doSomething();
}
@Singleton
public class SomethingImpl {
@Inject
AnotherThing anotherThing;
@Inject
public SomethingImpl() {
}
}
_
_@Module
_を使用して、特定の実装をインターフェイスに「バインド」する必要があります。
_@Module
public class SomethingModule {
@Provides
Something something(SomethingImpl something) {
return something;
}
}
_
Dagger 2.4以降の短縮形は次のとおりです。
_@Module
public abstract class SomethingModule {
@Binds
abstract Something something(SomethingImpl something);
}
_
4.)Injector
クラスを作成して、アプリケーションレベルのコンポーネントを処理します(モノリシックObjectGraph
を置き換えます)
(注:APTを使用してDaggerApplicationComponent
ビルダークラスを作成する_Rebuild Project
_)
_public enum Injector {
INSTANCE;
ApplicationComponent applicationComponent;
private Injector(){
}
static void initialize(CustomApplication customApplication) {
ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
.appContextModule(new AppContextModule(customApplication))
.build();
INSTANCE.applicationComponent = applicationComponent;
}
public static ApplicationComponent get() {
return INSTANCE.applicationComponent;
}
}
_
5.)CustomApplication
クラスを作成
_public class CustomApplication
extends Application {
@Override
public void onCreate() {
super.onCreate();
Injector.initialize(this);
}
}
_
6.)CustomApplication
を_AndroidManifest.xml
_に追加します。
_<application
Android:name=".CustomApplication"
...
_
7.)クラスをMainActivity
に挿入する
_public class MainActivity
extends AppCompatActivity {
@Inject
CustomApplication customApplication;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Injector.get().inject(this);
//customApplication is injected from component
}
}
_
8。)お楽しみください!
+1。)作成できるコンポーネントにScope
を指定できますActivity-level scoped components。サブスコープを使用すると、アプリケーション全体ではなく、特定のサブスコープにのみ必要な依存関係を提供できます。通常、各アクティビティはこのセットアップで独自のモジュールを取得します。スコーププロバイダーが存在することに注意してくださいコンポーネントごと、つまり、そのアクティビティのインスタンスを保持するためには、コンポーネント自体が構成の変更に耐えなければなりません。たとえば、onRetainCustomNonConfigurationInstance()
またはMortarスコープを介して存続できます。
サブスコープの詳細については、 ガイドby Google をご覧ください。また、 このサイトのプロビジョニング方法 および コンポーネントの依存関係セクション )および here もご覧ください。 。
カスタムスコープを作成するには、スコープ修飾子の注釈を指定する必要があります。
_@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}
_
サブスコープを作成するには、コンポーネントのスコープを指定し、その依存関係としてApplicationComponent
を指定する必要があります。モジュールプロバイダーメソッドでもサブスコープを指定する必要があることは明らかです。
_@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
_
そして
_@Module
public class CustomScopeModule {
@Provides
@YourCustomScope
public CustomScopeClass customScopeClass() {
return new CustomScopeClassImpl();
}
}
_
oneスコープコンポーネントのみを依存関係として指定できることに注意してください。 Javaで多重継承がサポートされていないのとまったく同じように考えてください。
+2.) _@Subcomponent
_について:基本的に、スコープ付きの_@Subcomponent
_はコンポーネントの依存関係を置き換えることができます。ただし、注釈プロセッサが提供するビルダーを使用するのではなく、コンポーネントファクトリメソッドを使用する必要があります。
したがって、この:
_@Singleton
@Component
public interface ApplicationComponent {
}
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
_
これになります:
_@Singleton
@Component
public interface ApplicationComponent {
YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}
@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
CustomScopeClass customScopeClass();
}
_
この:
_DaggerYourCustomScopedComponent.builder()
.applicationComponent(Injector.get())
.customScopeModule(new CustomScopeModule())
.build();
_
これになります:
_Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());
_
+3.): Dagger2に関する他のStack Overflowの質問も確認してください。多くの情報が提供されています。たとえば、現在のDagger2構造は this answer で指定されています。
ありがとう
Github 、 TutsPlus 、 Joe Steele 、 Froger MCS および Google 。
また、この ステップバイステップの移行ガイドについては、この投稿を書いた後に見つけました。
また、 スコープの説明 についてはキリル。
公式ドキュメンテーション のさらに詳しい情報。
Dagger 1.xのガイド:
手順は次のとおりです。
1.)Dagger
を依存関係の_build.gradle
_ファイルに追加します
_dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
...
compile 'com.squareup.dagger:dagger:1.2.2'
provided 'com.squareup.dagger:dagger-compiler:1.2.2'
_
また、_packaging-option
_に関するエラーを防ぐために_duplicate APKs
_を追加します。
_Android {
...
packagingOptions {
// Exclude file to avoid
// Error: Duplicate files during packaging of APK
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
}
_
2.)Injector
クラスを作成して、ObjectGraph
を処理します。
_public enum Injector
{
INSTANCE;
private ObjectGraph objectGraph = null;
public void init(final Object rootModule)
{
if(objectGraph == null)
{
objectGraph = ObjectGraph.create(rootModule);
}
else
{
objectGraph = objectGraph.plus(rootModule);
}
// Inject statics
objectGraph.injectStatics();
}
public void init(final Object rootModule, final Object target)
{
init(rootModule);
inject(target);
}
public void inject(final Object target)
{
objectGraph.inject(target);
}
public <T> T resolve(Class<T> type)
{
return objectGraph.get(type);
}
}
_
3.)RootModule
を作成して、将来のモジュールをリンクします。 _@Inject
_アノテーションを使用するすべてのクラスを指定するには、injects
を含める必要があることに注意してください。そうしないと、DaggerがRuntimeException
をスローします。
_@Module(
includes = {
UtilsModule.class,
NetworkingModule.class
},
injects = {
MainActivity.class
}
)
public class RootModule
{
}
_
4.)ルートで指定されたモジュール内に他のサブモジュールがある場合、それらのモジュールを作成します:
_@Module(
includes = {
SerializerModule.class,
CertUtilModule.class
}
)
public class UtilsModule
{
}
_
5.)依存関係をコンストラクターパラメーターとして受け取るリーフモジュールを作成します。私の場合、循環依存関係はなかったので、Daggerがそれを解決できるかどうかはわかりませんが、ありそうにないと思います。 _complete = false
_を指定した場合、コンストラクタパラメータもDaggerによってモジュールで提供する必要があります。他のモジュールでも使用できます。
_@Module(complete = false, library = true)
public class NetworkingModule
{
@Provides
public ClientAuthAuthenticator providesClientAuthAuthenticator()
{
return new ClientAuthAuthenticator();
}
@Provides
public ClientCertWebRequestor providesClientCertWebRequestor(ClientAuthAuthenticator clientAuthAuthenticator)
{
return new ClientCertWebRequestor(clientAuthAuthenticator);
}
@Provides
public ServerCommunicator providesServerCommunicator(ClientCertWebRequestor clientCertWebRequestor)
{
return new ServerCommunicator(clientCertWebRequestor);
}
}
_
6.)Application
を拡張し、Injector
を初期化します。
_@Override
public void onCreate()
{
super.onCreate();
Injector.INSTANCE.init(new RootModule());
}
_
7.)MainActivity
で、onCreate()
メソッドでインジェクターを呼び出します。
_@Override
protected void onCreate(Bundle savedInstanceState)
{
Injector.INSTANCE.inject(this);
super.onCreate(savedInstanceState);
...
_
8.)MainActivity
で_@Inject
_を使用します。
_public class MainActivity extends ActionBarActivity
{
@Inject
public ServerCommunicator serverCommunicator;
...
_
エラー_no injectable constructor found
_を受け取った場合は、_@Provides
_注釈を忘れていないことを確認してください。