なぜ依存性注入を使用するのでしょうか? 新しいオブジェクトを直接作成するのは良いことではありませんか? なぜ単純な問題を複雑にするのでしょうか?

作者: にゅーき

なぜ依存性注入を使用するのでしょうか? 新しいオブジェクトを直接作成するのは良いことではありませんか? なぜ単純な問題を複雑にするのでしょうか?

自分のスキルを誇示しているのか、それとも13歳のふりをしているのか?

私が使用している Dagger2 が本当に誇示されているのであれば、これは実際には当てはまりません、注意してください。Dagger には落とし穴もたくさんあります。大規模なプロジェクトで Dagger をうまく使用できるのは本当に素晴らしいことですが、今ではみんな Hilt を使っています。何をインストールできますか? 使い方はとても簡単で、すべてシーンベースのものです。いくつか修正されました。使用法。必要ありません必要ありません。

本題に戻りますが、なぜ依存性注入を使用するのでしょうか? 依存関係の注入が推奨されるのはどのような場合ですか? 依存性注入を使用したい場合でも、依存性注入に Hilt が推奨されるのはなぜですか?

1. 自動管理 (柔軟性と分離)

まず第一に、プロジェクトを書くときに依存関係注入を使用しなければならないという意味ではありません。プロジェクトが大規模なプロジェクトでない場合は、合計で 5 ページ、6 ページ、または 10 ページ以上しかありません。依存性注入フレームワーク 大規模なプロジェクトの場合はモジュールに分割する コンポーネントは複数人で共同開発するため、依存するオブジェクトが非常に複雑であったり、入れ子人形のようなオブジェクトの依存関係があったりするため、非常に便利です柄。さまざまなモジュール/コンポーネントの開発者は、独自のコンポーネント/モジュールでオブジェクト プロビジョニング メソッドを直接定義し、関係の依存関係や実装ロジックの複雑さを必要とせずに、それを反対側で直接使用します。

いくつかの複雑なネストされた依存関係を見てみましょう。たとえば、3 層の人形の依存関係を見てみましょう。

@Singleton
class UserServer @Inject constructor(private val userDao: UserDao) {

    fun testUser() {
        YYLogUtils.w(userDao.printUser())
        toast(userDao.printUser())
    }

    fun getDaoContent():String{
        return userDao.printUser()
    }

}

@Singleton
class UserDao @Inject constructor(private val user: UserBean) {

    fun printUser(): String {
        return user.toString()
    }

}

data class UserBean(
    val name: String,
    val age: Int,
    val gender: Int,
    val languages: List<String>
)

他の 3 つのクラスはすべて必要ですが、実際には、UserBean オブジェクトを提供するクラスがもう 1 つあります。

@Module
@InstallIn(SingletonComponent::class)
class Demo10DIModule {

    @Singleton
    @Provides
    fun provideUser(): UserBean {
        return UserBean("newki", 18, 1, listOf("中文", "英文"))
    }

}

使用:

@AndroidEntryPoint
class Demo10DIActivity : BaseVMActivity() {

    @Inject
    lateinit var userServer: UserServer

    override fun getLayoutIdRes(): Int = R.layout.activity_demo10_di

    override fun init() {
        findViewById<Button>(R.id.btn_01).click {
            YYLogUtils.w(userServer.toString())
            userServer.testUser()
        }
    }

Hilt を使用しない場合は、独自の新しいオブジェクトを実装することもできます

class Demo10DIActivity : BaseVMActivity() {

    lateinit var userServer: UserServer

    override fun getLayoutIdRes(): Int = R.layout.activity_demo10_di

    override fun init() {
        //自己new三个对象
         userServer = UserServer(UserDao(UserBean("newki", 18, 1, listOf("中文", "英文"))))

        findViewById<Button>(R.id.btn_01).click {
            YYLogUtils.w(userServer.toString())
            userServer.testUser()
        }
    }

このように、新しいオブジェクトは、ライフサイクルがページに従うことは言うまでもなく、単一のインスタンスを維持することはできません。要件が変更された場合、UseDao で UserBean と UserProfile が必要になるとします。新しいオブジェクトの場合は、次のことが必要です。どこでも変更するには、Hilt メソッドの場合は、UserDao オブジェクトの構造を変更するだけで済みます。

@Singleton
class UserDao @Inject constructor(private val user: UserBean,private val profile:UserProfile) {

    fun printUser(): String {
        return user.toString()
    }

}

上記は単なる例ですが、オブジェクトを構築するには他のオブジェクトを多数構築する必要があり、他のオブジェクトの構築も同様に複雑で順番に構築する必要があり、必要なオブジェクトのライフサイクルも異なります。一部のライフ サイクルは Like アクティビティとは異なる場合があり、一部はシングルトンである場合があるため、構築時にオブジェクトのライフ サイクルとオブジェクトのソースも考慮する必要があります。

特に大規模なプロジェクトの場合、プロジェクトは一人で書くのではなく、全員で協力して開発するため、非常に苦痛です。他人のコードを見るのは聖書を読むようなもので、目的がどのようになっているのかわかりません。オブジェクトの構築方法が変更されると、その変更は構築プロセス全体と関連するコードに影響し、本体全体に影響を及ぼします。

このとき、依存関係注入フレームワークが役に立ちます。関数、オブジェクトの依存関係、ライフ サイクルの実装方法に集中するだけでよく、管理は任せてください。Inject は、依存関係に応じて必要なものを注入するのに役立ちます。オブジェクトであり、各オブジェクトのライフサイクルを管理し、ライフサイクルが終了していない場合は新たに繰り返されません。

したがって、Hilt 依存関係注入は大規模プロジェクトに非常に適しています。小規模プロジェクト開発者は、プロジェクトの複雑さが低いため、これらの問題に遭遇したことがないため、Hilt 依存関係注入が使用される理由を理解しておらず、単純な新しいオブジェクトを使用する必要があるのではないかと疑問に思っています。とても複雑になります。

2. ライフサイクル管理

ここで言うオブジェクトのライフサイクルとは、実際にはある範囲のライフサイクルのことであり、ある範囲内のシングルトンというのはちょっと浅いかもしれません。

グローバル シングルトン オブジェクトを使用しない限り、新しいオブジェクトのライフ サイクルを直接制御することはできませんが、Hilt 依存関係注入を通じてオブジェクトのライフ サイクル制御を簡単に実現できます。

たとえば、通常のオブジェクトの高速注入方法では、シングルトンに直接アノテーションを付けると、グローバル スコープのシングルトンがマークされます。

@Singleton
class UserServer @Inject constructor(private val userDao: UserDao) {

    fun testUser() {
        YYLogUtils.w(userDao.printUser())
        toast(userDao.printUser())
    }

    fun getDaoContent():String{
        return userDao.printUser()
    }

}

もう 1 つの使用法は、モジュールを使用して依存性注入を定義し、SingletonComponent + Singleton を使用すると、グローバル スコープのシングルトンも意味します。

@Module
@InstallIn(SingletonComponent::class)
class Demo10DIModule {

    @Singleton
    @Provides
    fun provideUser(): UserBean {
        return UserBean("newki", 18, 1, listOf("中文", "英文"))
    }

}

Activity 内にシングルトンが必要な場合は、Activity スコープ内のシングルトンである ActivityComponent + ActivityScoped を使用します。

@Module
@InstallIn(ActivityComponent::class)
class Demo10DIModule {

    @ActivityScoped
    @Provides
    fun provideUser(): UserBean {
        return UserBean("newki", 18, 1, listOf("中文", "英文"))
    }

}

上記の 2 つは比較的よく使用されるスコープですが、その他についても、Fragment のシングルトン、View のシングルトンなども同様に使用されるようにすることができます。

したがって、依存オブジェクトのライフサイクル制御も、新しいオブジェクトを使用することによって実現できない、Hilt の非常に便利な機能です。

3. 他の依存性注入との比較

現在Androidの主流はDagger2 Hilt Koinの3種類の依存性注入です。

以前のKoinと比較すると、Kotlin言語環境でのみ使用できます。そして、パフォーマンスはヒルトよりも優れているわけではありません。エラーメッセージも親切ではありません。

Dagger2 は使えないわけではありません 2017 年、2018 年に流行しましたが学習コストが非常に高く、UI 依存性注入クラスを作成するたびに mackproject をしなければならず、エラープロンプトも親切ではありません。

実は、私は Dagger2 を 17 年間使用しており、デモとフレームワークのパッケージを自分で作成しましたが、その後のプロジェクトでは使用しませんでした。同僚はその使い方を知りませんし、学習コストが高すぎます。Dagger2の使用も諦めます。

Hilt は実際には Daggert2 の Android シナリオ実装です。Dagger2 は内部的にカプセル化されています。Android 開発で Hilt を使用するのが簡単で、学習コストが非常に低く、エラー プロンプトがフレンドリーです。また、ViewModel に注入することもできます。したがって、Android 開発用に設計されています。

注入されたオブジェクトのメモリ使用量が最適化されているかどうかについては、メモリの最適化があることを指摘する記事や公式ドキュメントはなく、ページ全体に複数の注入されたオブジェクトがある場合は、直接新しいオブジェクトと比較して、私自身のテストのみが示していると感じます注入されたオブジェクトが占有するメモリが少し少ないということですが、テストの変動によるものなのかはわかりません。理解できません。

要約する

Hilt を使用する必要がある理由をまとめます。

  1. 怠惰; 自動管理、複数のオブジェクトの自動挿入、変更があった場合に備えて、死体の山の中で横たわる必要はありません。
  2. シングルトン。独自に手動でシングルトンを作成せずに、オブジェクトにライフサイクルを持たせ、手動でログアウトします。
  3. デカップリング: 特にコンポーネント化されたプロジェクトの場合、不要なオブジェクトをどこにでも導入する必要がなく、別のコンポーネントが挿入されるだけで、コンポーネント内で参照するだけです。

私がヒルトを使っていて一番惹かれるポイントはこの3つだと思います。

2022 年現在、依存性注入には Hilt をお勧めします。キーは使いやすいです。Android の一般的なシナリオでいくつかのデモも作成しました。合計で非常に多くの固定使用法があります。Android 開発のほとんどの使用シナリオをカバーするデモを以前に書きました。必要な場合は、前回の記事をご覧ください。

ちなみに、これは外国人プログラマーにとって必須の面接スキルですが、海外の Android 開発者は国内開発者に比べて特に Dagger2 や Hilt を好んで使用しており、古いプロジェクトでは Dagger2 を使用していることが多いです。

Androidの勉強メモ

Android パフォーマンスの最適化: https://qr18.cn/FVlo89
Android Vehicle: https://qr18.cn/F05ZCM
Android リバース セキュリティ調査ノート: https://qr18.cn/CQ5TcL
Android フレームワークの原則: https://qr18.cn/AQpN4J
Android オーディオとビデオ: https://qr18.cn/Ei3VPD
Jetpack (Compose を含む): https://qr18.cn/A0gajp
Kotlin: https://qr18.cn/CdjtAF
Gradle: https://qr18.cn/DzrmMB
OkHttp ソース コード分析ノート: https://qr18.cn/Cw0pBD
Flutter: https://qr18.cn/DIvKma
Android Eight Knowledge Body: https://qr18.cn/CyxarU
Android Core Notes: https://qr21.cn/CaZQLo
Android過去の面接の質問: https://qr18.cn/CKV8OZ
2023 年最新の Android 面接の質問集: https://qr18.cn/CgxrRy
Android 車両開発の就職面接の演習:https://qr18.cn/FTlyCJ
音声とビデオの面接の質問:https://qr18.cn/AcV6Ap

おすすめ

転載: blog.csdn.net/weixin_61845324/article/details/132494653