匕首线切割图纸下载_匕首2-利用范围和子组件

匕首线切割图纸下载

范围的含义是什么? (What is the meaning of scope?)

Scope refers to the lifetime of an object. Consider an example of a simple class.

范围是指对象的生存期。 考虑一个简单类的例子。

class MyClass {
  
  // It's scope is tied to the lifetime of the class
  var largerScope = 100
  
  fun myFunction() {
    // It's scope is tied to the lifetime of the function 
    var smallerScope = 10
  }
}
  • largeScope — Its scope is tied to the lifetime of the class. It can be accessed anywhere in the class.

    largeScope其范围与类的生存期相关。 可以在班上的任何地方访问它。

  • smallerScope — Its scope is limited to the lifetime of a function. It can only be accessed inside the myFunction block. It is not recognized outside this function.

    smallerScope范围-其范围仅限于函数的生存期。 只能在myFunction块内部访问它。 在此功能之外无法识别。

  • Scopes are meant to define the Object’s lifetime.

    范围旨在定义对象的生存期。

范围界定为何重要,在Dagger中有什么用? (Why is scoping important and what are its uses in Dagger?)

Scopes in dagger are nothing different. Consider a shopping app where you browse through the different screens(👇), add the products in the cart, and finally make payment.

匕首的作用范围没有什么不同。 考虑一个购物应用程序,您在其中浏览不同的屏幕(👇),将产品添加到购物车中,最后付款。

Image for post
Browsing and Payment screens
浏览和付款屏幕

Let’s look at how this can be implemented.

让我们看一下如何实现它。

  1. HomePage, CategoryPage and BrandPage are the browsing screens that depend on the ProductRepository.

    HomePageCategoryPageBrandPage是取决于ProductRepository的浏览屏幕。

  2. PaymentPage depends on PaymentRepositoryto make payments.

    PaymentPage取决于PaymentRepository进行支付。

A common pattern is to create both the repositories at once when the application is started, store them in the Dagger graph, and provide them to the different screens. This is how it looks like. Appcomponent provides both the repositories.

一种常见的模式是在启动应用程序时立即创建两个存储库,将它们存储在Dagger图形中,然后将它们提供给不同的屏幕。 这就是它的样子。 Appcomponent提供了两个存储库。

@AppScope
@Component(modules = [AppModule::class])
interface AppComponent {
    fun inject(page: HomePage)
    fun inject(page: CategoryPage)
    fun inject(page: BrandPage)
    
    fun inject(page: PaymentPage)
}


@Module
class AppModule {


    @AppScope
    @Provides
    fun provideProductRepository(): ProductRepository = ProductRepository()
    
    @AppScope
    @Provides
    fun providePaymentRepository(): PaymentRepository = PaymentRepository()
}




class ShoppingApplication : Application() {


    lateinit var appComponent: AppComponent


    override fun onCreate() {
        super.onCreate()


        appComponent = DaggerAppComponent.builder().build()


    }
}

Using it for injection in HomePage and PaymentPage.

用于HomePage和PaymentPage中的注入。

class HomePage : AppCompatActivity() {


    @Inject
    lateinit var productRepository: ProductRepository


    override fun onCreate(savedInstanceState: Bundle?) {


        (application as ShoppingApplication)
            .appComponent
            .inject(homePage: this)
            
        // Can access productRepository here
    }
}


class PaymentPage : AppCompatActivity() {


    @Inject
    lateinit var productRepository: ProductRepository


    override fun onCreate(savedInstanceState: Bundle?) {


        (application as ShoppingApplication)
            .appComponent
            .inject(homePage: this)
            
        // Can access productRepository here
    }
}

The repositories created once at the application level live as long as the application is alive. The screens requesting them will get the same Repository instance.

只要应用程序处于活动状态,就可以在应用程序级别创建一次存储库。 请求它们的屏幕将获得相同的Repository实例。

Concerns: This is completely fine as often the repositories are stateless and act only as a helper class to fetch data from the API. But the problems arise when the repository does something more.

问题 :完全正常,因为存储库通常是无状态的,并且仅用作帮助类以从API提取数据。 但是,当存储库执行更多操作时,就会出现问题。

Suppose that PaymentRepository sets up SDKs of different payment vendors, runs an API service for keeping the session alive, and periodically sends location updates. In that case, the creation and handling of the repository would be a costly affair. It would require more time to get initialized and post that it continuously consumes resources like Network resources and Battery as long as it is alive.

假设PaymentRepository设置了不同付款供应商的SDK,运行了一个API服务以使会话保持活动状态,并定期发送位置更新。 在这种情况下,创建和处理存储库将是一项昂贵的事务。 只要它还处于活动状态,它将需要更多的时间进行初始化和发布,从而持续消耗诸如网络资源和电池之类的资源。

PaymentRepository problems = Initialisation + Resource consumption

PaymentRepository问题=初始化+资源消耗

How to overcome this? — It’s not often the case that every time you open the app, you end up making a purchase. So a better approach would be to,

如何克服呢? 每次打开应用程序时,最终都会进行购买的情况并不常见。 因此,更好的方法是

  • Create it only when needed [create it at T2]

    仅在需要时创建它[在T2创建]

  • Hold it only as long as the payment session is alive [destroy it at T3].

    仅在付款会话有效时才保留它(在T3销毁它)。

Image for post
Graphical representation of the scope
范围的图形表示

实作 (Implementation)

1.定义范围 (1. Defining scopes)

@javax.inject.Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class PaymentScope




@javax.inject.Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class AppScope

AppScope and PaymentScope are the two scopes. AppScope means the lifetime of the application and PaymentScope refers to that of the Payment feature. Scope gets a meaning when they are associated with the Component 👇.

AppScopePaymentScope是两个范围。 AppScope表示应用程序的生命周期, PaymentScope表示付款功能的生命周期。 当它们与Component associated关联时,作用域就具有含义。

2.创建AppComponent (2. Creating AppComponent)

@AppScope
@Component(modules = [AppModule::class])
interface AppComponent {
    fun inject(page: HomePage)
    fun inject(page: CategoryPage)
    fun inject(page: BrandPage)
}


@Module
class AppModule {


    @AppScope
    @Provides
    fun provideProductRepository(): ProductRepository = ProductRepository()
}




class ShoppingApplication : Application() {


    lateinit var appComponent: AppComponent


    override fun onCreate() {
        super.onCreate()


        appComponent = DaggerAppComponent.builder().build()


    }
}

AppComponent is associated with the AppScope. It is created in the ShoppingApplication class[Application-level]. As it is created at the application level, its graph is built only once when the app is started and is used throughout until the application is destroyed.

AppComponent与AppScope相关联。 它是在ShoppingApplication类[应用程序级别]中创建的。 由于它是在应用程序级别创建的,因此它的图形仅在应用程序启动时构建一次,并且在整个应用程序中使用直到被销毁。

Below is the demonstration of using AppComponent to inject the dependencies for the HomePage. The same can be done for the Category and Brand page.

下面是使用AppComponent注入HomePage依赖项的演示。 可以对“类别和品牌”页面执行相同的操作。

class HomePage : AppCompatActivity() {


    @Inject
    lateinit var productRepository: ProductRepository


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


        (application as ShoppingApplication)
            .appComponent
            .inject(homePage: this)
            
        // Can access productRepository here
    }
}

3.创建PaymentComponent (3. Creating PaymentComponent)

Unlike AppComponent which is created at the application-level, the Payment component is created at the payment feature level. This component can be of 2 types.

与在应用程序级别创建的AppComponent不同,“付款”组件是在付款功能级别创建的。 该组件可以有2种类型。

  • First, the PaymentComponent can request dependencies from another component(AppComponent). In that case, the PaymentComponent would be a subcomponent of AppComponent.

    首先, PaymentComponent可以从另一个组件( AppComponent )请求依赖AppComponent 。 在这种情况下,PaymentComponent将是AppComponent的子组件。

  • Secondly, the PaymentComponent can be a standalone component and satisfy all the dependencies by itself.

    其次, PaymentComponent可以是一个独立的组件,并且可以单独满足所有依赖性。

3.1 When PaymentComponent is dependent on AppComponent

3.1何时PaymentComponent依赖于AppComponent

AppComponent and PaymentSubcomponent have a parent-child relationship. Some of the dependencies required by the child are supplied by the parent. In that case, the component is defined as a subcomponent.

AppComponentPaymentSubcomponent具有父子关系。 子级所需的某些依赖项由父级提供。 在这种情况下,该组件被定义为子组件。

@PaymentScope
@Subcomponent(modules = [PaymentModule::class])
interface PaymentSubcomponent {


    @Subcomponent.Builder
    interface Builder {
        fun build(): PaymentSubcomponent
    }


    fun inject(page: PaymentPage)
}


@Module
class PaymentModule {


    // UserSession dependency shall be provided by the parent component
    @PaymentScope
    @Provides
    fun providePaymentRepository(userSession: UserSession): PaymentRepository = PaymentRepository()
}

@Subcomponent annotation means that it is a child component and for it to be built, it needs a parent component(AppComponent).

@Subcomponent批注意味着它是一个子组件,要构建它,需要一个父组件(AppComponent)。

UserSession dependency needed for the PaymentSubcomponent should be provided by its parent AppComponent.

PaymentSubcomponent所需的UserSession依赖关系应由其父AppComponent提供。

Note:Subcomponent has no idea about its parent. Its the ParentComponent’s resposibilty to include the subcomponent & provide the necessary dependencies.

注意:子组件不了解其父组件。 它的ParentComponent的责任是包括子组件并提供必要的依赖关系。

Accordingly, AppComponent should declare that it will satisfy the dependencies for PaymentSubcomponent. Below changes are required for AppComponent to act as a parent component. Notice that it provides the UserSession required for its child.

因此, AppComponent应该声明它将满足PaymentSubcomponent的依赖关系。 要使AppComponent充当父组件,需要进行以下更改。 请注意,它提供了其子级所需的UserSession

@AppScope
@Component(modules = [AppModule::class, SubcomponentModules::class])
interface AppComponent {
    
    // 1. PaymentSubcomponent can only be built through AppComponent
    fun subComponent(): PaymentSubcomponent.Builder


    fun inject(activity: HomePage)
}


@Module
class AppModule {


    @AppScope
    @Provides
    fun provideProductRepository(): ProductRepository = ProductRepository()
    
    // 2. Provides UserSession dependency required for its child component
    @AppScope
    @Provides
    fun provideUserSession(): UserSession = UserSession()
}
 
// 3. Declaring the Subcomponents that depend on AppComponent
@Module(subcomponents = [PaymentSubcomponent::class])
class SubcomponentModules

Using PaymentSubcomponent to provide dependencies in the PaymentPage👇🏻.

使用PaymentSubcomponent在PaymentPage👇🏻中提供依赖项。

class PaymentPage : AppCompatActivity() {


    @Inject
    lateinit var paymentRepository: PaymentRepository
    
    lateinit var paymentSubcomponent: PaymentSubcomponent


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


        paymentSubcomponent = (application as MainApplication)
            .appComponent
            .subComponent()
            .build()
            
        paymentSubcomponent.inject(this)
        
        // Can access paymentRepository here
    }
}

3.2 When Payment component is independent

3.2付款组件独立时

This is simple as it is satisfying all the dependencies itself. Declare it as a normal component and build it in the Payment page.

这很简单,因为它可以满足所有依赖项本身。 将其声明为常规组件并将其构建在“付款”页面中。

@PaymentScope
@Component(modules = [PaymentModule::class])
interface PaymentComponent {
    fun inject(page: PaymentPage)
}


@Module
class PaymentModule {
    
    // UserSession dependency is available in the PaymentComponent
    @PaymentScope
    @Provides
    fun provideUserSession(): PaymentRepository = UserSession()


    @PaymentScope
    @Provides
    fun providePaymentRepository(userSession: UserSession): PaymentRepository = PaymentRepository()
}
class PaymentPage : AppCompatActivity() {


    @Inject
    lateinit var paymentRepository: PaymentRepository
    
    lateinit var paymentComponent: PaymentComponent


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)


        paymentComponent = DaggerPaymentComponent
            .builder()
            .build()
            
        paymentComponent.inject(page = this)


        // Can access paymentRepository here
    }
}

In both the above cases,PaymentSubcomponent(3.1) & PaymentComponent(3.2) are created in the PaymentPage and they exist until the activity is destroyed. In that way, its scope is limited only to the lifetime of the PaymentPage.

在上述两种情况下, PaymentSubcomponent(3.1)PaymentComponent(3.2)都在PaymentComponent(3.2)中创建,并且它们一直存在直到活动被销毁为止。 这样,其范围仅限于PaymentPage的生存期。

Conclusion

结论

  • AppComponent is created at the Application level (in the Application class). So the time taken to build the graph of the AppComponent will affect the start-up time of the App. For better performance, consider only initializing the loggers, API clients, Crashltics, Analytics, User sessions, etc at the start.

    AppComponent在应用程序级别(在应用程序类中)创建。 因此,构建AppComponent图表所需的时间将影响App的启动时间。 为了获得更好的性能,请一开始只考虑初始化记录器,API客户端,Crashltics,Analytics,用户会话等。
  • Notice that the PaymentComponent and PaymentSubcomponent is built only when the app navigates to the Payment page limiting its lifetime. It gets destroyed when the PaymentPage is destroyed.

    请注意,仅当应用程序导航到“付款”页面并限制其生命周期时, PaymentSubcomponent构建PaymentComponentPaymentSubcomponent 。 当PaymentPage被销毁时,销毁它。

  • Henceforth, it's well-advised to segregate the dependencies into different components rather than incorporating everything into a single AppComponent. This way you have the capability to control their lifetime.

    从今以后,建议将依赖项隔离到不同的组件中,而不是将所有内容都合并到一个AppComponent中。 这样,您就可以控制其寿命。

You can also look at Dependent components which is similar to Subcomponents. But inversely, the subcomponent is aware of the parent component and the parent component has no idea of its dependents. This is useful when working with Dynamic Feature modules.

您还可以查看与子组件类似的从属组件。 但是相反,子组件知道父组件,而父组件不知道其依赖项。 在使用动态功能模块时,这很有用。

翻译自: https://levelup.gitconnected.com/dagger-2-leveraging-subcomponents-and-scopes-2aef78a291c9

匕首线切割图纸下载

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值