短剣2から ドキュメント@Singleton
注釈付きクラスを持つことができることに気付きました。クラスで@Singleton
としてマークする目的は何ですか。コードでこれを実行しようとしましたが、シングルトンオブジェクトは生成されません。このアノテーションを使用してクラスにマークを付けると、どのような用途があるのかわかりません。
ドキュメントから、次のステートメントに注目してください。
注入可能なクラスの@Singletonアノテーションもドキュメントとして機能します。このクラスは複数のスレッドで共有される可能性があることを潜在的なメンテナーに思い出させます。*
@Singleton
class CoffeeMaker {
...
}
更新:froger_mcsの回答を確認した後、Dagger 2では、モジュールORコンストラクターインジェクションによってインジェクションを提供できることがわかります。したがって、モジュールではありませんが、次のクラスをインジェクトできます。
@Singleton
public class MyClass {
@Inject
public MyClass() {
}
}
このバージョンでは、コンストラクターが注入され、Androidアクティビティで次のことを行うだけで提供されます:
@Inject
MyClass myClass;
//then in onCreate actually inject(this) from your graph of course.
@Singleton
(および他のスコープアノテーション)は、クラスを依存関係グラフ内の単一インスタンスにします(コンポーネントオブジェクトが存在する限り、このインスタンスは「シングルトン」になることを意味します)。
要するに-あなたが注入するたびに@Singleton
注釈付きクラス(@Inject
注釈)同じコンポーネントから注入する限り、同じインスタンスになります。
詳細については、ブログ投稿で@Singleton
およびその他のスコープアノテーションはDagger 2で機能します。 http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/
_@Singleton
_は実際にはシングルトンを作成しません。単にScope
であり、_@Singleton
_を使用しないことをお勧めします。誤解を招く可能性があります。 。
データベースの依存関係に_@Singleton
_注釈を付け、Component
にリンクするとします。今、このComponent
をActivities
A
とB
で初期化するとします。2つのActivities
にデータベースの異なるインスタンスがあります。欲しくない。
これをどのように克服しますか?
Component
クラスでApplication
を一度初期化し、Activities
やFragments
などの他の場所で静的にアクセスします。20個を超える_Component's
_を持っている場合、Application
クラスですべてを初期化できないため、すぐに手に負えなくなる可能性があります、そうすると、アプリの起動時間が遅くなります。
私による最良の解決策は、ダブルチェックまたは他のバリアントの実際のSingleton
を作成し、これをgetInstance()
として静的に使用し、これをモジュールの_@Provides
_の下で使用することです。
私もそれが私の心を壊すことを知っていますが、_@Singleton
_は実際にはSingleton
ではなく、Scope
であることを理解してください。
シングルトンとは何ですか?
Androidのシングルトンパターン
アプリケーションの存続期間中、グローバルインスタンス自体へのアクセスポイントを提供するクラスの単一インスタンス。
ダガーの@Singletonアノテーション
特定のコンポーネントに固有のクラスの単一インスタンス、そのアクセスはコンポーネントのスコープに制限されます。
シングルトンの目的
依存関係グラフ(コンポーネント)内でクラスの単一インスタンスを提供するため。コンポーネントは通常、アプリケーションレベルで初期化されます。これは、コンポーネントがアプリケーションの有効期間全体にわたってコンポーネントのみを実行し、すべてのアクティビティとフラグメントからアクセスできるためです。
例を見てみましょう。
CoffeeComponent.kt
@Singleton
@Component
interface CoffeeComponent {
fun getCoffeeMaker():CoffeeMaker
fun inject(activityA: ActivityA)
fun inject(activityB: ActivityB)
}
CoffeeMaker.kt
@Singleton
class CoffeeMaker @Inject constructor()
CoffeeAplication.kt
class CoffeeApplication : Application() {
private val component by lazy {
DaggerCoffeeComponent.builder().build()
}
fun getAppComponent(): CoffeeComponent = component
}
推奨プラクティス
常にコンポーネントの遅延初期化を行ってください。
シナリオ:たとえば、初期画面でコンポーネントを必要としないオンボーディング/チュートリアル画面を追加するか、他のデザインを組み込むことを決めた場合、起動遅延を最小限に抑えることができます。常に覚えておいてください、コンポーネントの初期化は高価です。
ActivityA.kt
import dagger.Lazy
class ActivityA: AppCompatActivity() {
@Inject
lateinit var coffeeMaker1:Lazy<CoffeeMaker>
@Inject
lateinit var coffeeMaker2:Lazy<CoffeeMaker>
private val component by lazy {
(application as CoffeeApplication).getAppComponent()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_activityB.setOnClickListener { startActivity(Intent(this, NewActivity::class.Java)) }
component.inject(this)
println("Activity A CoffeeMaker 1 - ${coffeeMaker1.get()}")
println("Activity A CoffeeMaker 2 - ${coffeeMaker2.get()}")
}
}
クラスの構築に費用がかかる場合は、短剣のLazy初期化を使用してください。これをkotlinのLazyと混同しないでください。インポートする必要があります
import dagger.Lazy
@Inject
lateinit var coffeeMaker1:Lazy<CoffeeMaker>
ActivityB.kt
class ActivityB: AppCompatActivity() {
@Inject
lateinit var coffeeMaker1:Lazy<CoffeeMaker>
@Inject
lateinit var coffeeMaker2:Lazy<CoffeeMaker>
private val component by lazy {
(application as CoffeeApplication).getAppComponent() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new)
component.inject(this)
println("Activity B CoffeeMaker 1 - ${coffeeMaker1.get()}")
println("Activity B CoffeeMaker 2 - ${coffeeMaker2.get()}")
}
}
次のようなログ出力が得られます
注:
If you want to share a singleton instance between activities, lazily initialize them in the application level, if you initialize them in an activity you will end up with different instance as the components are different
さて、手動で注釈を作成できます。これはsingletonオブジェクトの作成に役立ちます。
_@Scope
@Retention(RetentionPolicy.CLASS)
public @interface MyApplicationScope {
}
_
_@MyApplicationScope
_注釈が_@Provides
_注釈とともに追加されると、オブジェクトを一度だけ作成し、将来同じオブジェクトを使用するように短剣になります。 覚えておいてくださいコンポーネントインターフェイスにこの注釈を追加すると、コンパイル中にスコープ関連のエラーが発生します。
_@Singleton
_注釈を使用している場合、.build()
を使用してコンポーネントを作成するたびに、新しいオブジェクトを作成することになります。