简体   繁体   English

“注入一切”在Android中是一种不好的做法吗?

[英]Is “inject everything” a bad practice in Android?

Studying about dependency injection I found some approaches that suggests to inject everything and other saying that it's not necessary to do so . 关于依赖注入的研究我发现一些方法建议注入所有东西,而另一些方法则说没有必要这样做

In my current project, my rule of thumb regarding Dependency Injection is " if the class was created by me, I make it injectable ". 在我目前的项目中,关于依赖注入的经验法则是“ 如果该类是由我创建的,那么我可以将其注入 ”。 In other words only classes like SimpleDateFormat , ArrayList , HashMap are newables in my project. 换句话说,只有像SimpleDateFormatArrayListHashMap这样的类才是我项目中的新功能。 My intent doing this approach is that I can @Inject any class anywhere once calling Injector.getApplicationComponent().inject(this) in the Activity . 我做这种方法的意图是,一旦在Activity调用Injector.getApplicationComponent().inject(this) ,我就可以@Inject任何类。 Basically all my classes have a non-args constructor with @Inject . 基本上我的所有类都有一个带@Inject的非args构造函数。

I was primary using DI because I thought it will improve the performance and memory usage once the new operator is used exclusively by the Dagger generated classes. 我主要使用DI,因为我认为一旦new运算符由Dagger生成的类专门使用,它将改善性能和内存使用。 But I read a post from Dagger 1 developer saying that DI does not have impact on performance and the usage is basically to reduce boilerplate. 但我读了Dagger 1开发人员的帖子 ,说DI对性能没有影响,用法基本上是为了减少样板。

The first question is: 第一个问题是:

  • Dagger 2 does not any performance advantage in Android application? Dagger 2在Android应用程序中没有任何性能优势?

My project is running without problems and I think the approach of "inject everything" helps organizing better, despite some drawbacks. 我的项目运行没有问题,我认为“注入一切”的方法有助于更好地组织,尽管有一些缺点。

An example of usage of this approach is the following class: 使用此方法的一个示例是以下类:

public class TimelineEntryAdapter {

@Inject
Provider<TwitterEntry> mTwitterProvider;

@Inject
Provider<InstagramEntry> mInstagramProvider;

@Inject
Provider<FacebookEntry> mFacebookProvider;

@Inject
TimelineEntryComparator mComparator;

@Inject
public TimelineEntryAdapter() {
}

The second question is: 第二个问题是:

  • Is it a bad practice to inject everything in Android? 在Android中注入所有东西是不好的做法?

If the answer for the second question is "No", there is a better way to handle the non-args constructor to create classes? 如果第二个问题的答案是“否”,那么有一种更好的方法来处理非args构造函数来创建类吗? Because when I create an non-args constructor with @Inject annotation and a class need some parameters to work with, I must use setters : 因为当我用@Inject注释创建一个非args构造函数并且一个类需要一些参数来处理时,我必须使用setters

public class SavelArtist {

private MusicBrainzArtist mMusicBrainzArtist;

private DiscogsArtist mDiscogsArtist;

private List<SavelTweet> mTweetList;

private SpotifyArtist mSpotifyArtist;

private List<SavelInstagram> mInstaTimeline;

private List<SavelFacebook> mFacebookTimeline;

private List<SavelRelease> mReleases;

@Inject
Provider<SavelRelease> mReleaseProvider;

@Inject
public SavelArtist() {
}

public void setMusicBrainzArtist(MusicBrainzArtist mbArtist) {
    mMusicBrainzArtist = mbArtist;
}

public void setDiscogsArtist(DiscogsArtist discogsArtist) {
    mDiscogsArtist = discogsArtist;
}

public void setTweetList(List<SavelTweet> tweetList) {
    mTweetList = tweetList;
}

public void setSpotifyArtist(SpotifyArtist spotifyArtist) {
    mSpotifyArtist = spotifyArtist;
}

public void setInstaTimeline(List<SavelInstagram> instaTimeline) {
    mInstaTimeline = instaTimeline;
}

public void setFacebookTimeline(List<SavelFacebook> fbTimeline) {
    mFacebookTimeline = fbTimeline;
}

All the parameters could be set on the constructor, once all are get at the same time in the flow. 一旦所有参数在流程中同时获得,所有参数都可以在构造函数上设置。

Studying about dependency injection I found some approaches that suggests to inject everything and other saying that it's not necessary to do so. 关于依赖注入的研究我发现一些方法建议注入所有东西,而另一些方法则说没有必要这样做。

The froger_mcs blog entry you quote doesn't advocate injecting everything. 您引用的froger_mcs博客条目并不主张注入所有内容。 It quite clearly states: 它非常明确地指出:

The purpose of this post is to show what we can do, not what we should do. 这篇文章的目的是展示我们可以做什么,而不是我们该做什么。

And it goes on to state a disadvantage of injecting everything: 它继续说明注入一切的缺点:

If you want to use Dagger 2 for almost everything in your project you will quickly see that big piece of 64k methods count limit is used by generated code for injections. 如果您想在项目中使用Dagger 2几乎所有内容,您很快就会看到生成的代码用于注入的64k方法计数限制。

Now, on to your questions: 现在,问你的问题:

Dagger 2 does not any performance advantage in Android application? Dagger 2在Android应用程序中没有任何性能优势?

While Dagger 2 offers a performance advantage over other reflection-based DI frameworks (such as Guice) it doesn't claim to offer any performance advantage over manually constructing your object graphs by calling constructors. 虽然Dagger 2提供了优于其他基于反射的DI框架(例如Guice)的性能优势,但它并不声称通过调用构造函数来手动构建对象图提供任何性能优势。 You can inspect the generated classes yourself to see that these indeed still eventually call constructors. 您可以自己检查生成的类,看看这些确实最终仍然调用构造函数。

Is it a bad practice to inject everything in Android? 在Android中注入所有东西是不好的做法?

Well let's take the following very common Android code: 好吧,让我们采取以下非常常见的Android代码:

Intent nextActivity = new Intent(this, NextActivity.class);
startActivity(nextActivity);

Should we extract an IntentFactory and inject this using Dagger 2 merely to avoid the new keyword here? 我们应该提取一个IntentFactory并使用Dagger 2注入它只是为了避免使用new关键字吗? At this point, it is easy to approach pedantry. 在这一点上,很容易接近迂腐。 The advice in the other answer you quoted about the difference between injectables and newables is more flexible and elegant. 您引用另一个答案中关于注射剂和新品之间差异的建议更灵活,更优雅。

Moving on to your next question: 继续你的下一个问题:

If the answer for the second question is "No", there is a better way to handle the non-args constructor to create classes? 如果第二个问题的答案是“否”,那么有一种更好的方法来处理非args构造函数来创建类吗? Because when I create an non-args constructor with @Inject annotation and a class need some parameters to work with, I must use setters: 因为当我用@Inject注释创建一个非args构造函数并且一个类需要一些参数来处理时,我必须使用setter:

Using setters is the wrong approach for parameters. 使用setter是参数的错误方法。 You should distinguish dependencies and parameters . 您应该区分依赖项参数 Dependencies normally have the same lifecycle as the object itself. 依赖关系通常与对象本身具有相同的生命周期。 During the lifetime of the object, the methods exposed for that object may be called with different parameters. 在对象的生命周期中,可以使用不同的参数调用为该对象公开的方法。

I'm not a professional at dependency-management but I use it in my company so here's how I see it. 我不是依赖管理的专业人士,但我在公司使用它,所以这就是我看到它的方式。

Inject everything is basically good. 注入一切基本上都是好的。 I make everything that is used somewhere else ( other modules, classes, packages ) injectable and only static things ( static classes with hidden constructor ), things that get only used internally non injectable. 我将在其他地方使用的所有内容(其他模块,类,包)可注入,只使用静态内容(具有隐藏构造函数的静态类),仅在内部使用不可注入的内容。

What's the advantage of it? 它的优点是什么? Well The dependency system will take care of getting the instance and to discard it. 好依赖系统将负责获取实例并丢弃它。 It will clean up automatically. 它会自动清理。 Also using scopes on the classes will enable you to make a class that always has only one instance in the whole application ( multiple threads access it) or make it reusable ( every thread that needs it get's an own instance ). 同样在类上使用作用域将使您能够创建一个在整个应用程序中始终只有一个实例的类(多个线程访问它)或使其可重用(需要它的每个线程都是一个自己的实例)。

Also I think you could clean up your classes like this: 另外我认为你可以像这样清理你的课程:

@Reusable (Maybe a good Idea?)
public class SavelArtist {

private MusicBrainzArtist mMusicBrainzArtist;

private DiscogsArtist mDiscogsArtist;

private List<SavelTweet> mTweetList;

private SpotifyArtist mSpotifyArtist;

private List<SavelInstagram> mInstaTimeline;

private List<SavelFacebook> mFacebookTimeline;

private List<SavelRelease> mReleases;

private Provider<SavelRelease> mReleaseProvider;

public SavelArtist() {
}

@Inject
public void init(Provider<SavelRelease> mReleaseProvider) {
  this.mReleaseProvider = mReleaseProvider;
}

Think about always declaring the scope of the class. 考虑总是宣布课程的范围。 Is it a Singleton? 是单身人士吗? Will it be reusable? 它可以重复使用吗? This little detail can save you, once the application get's complex and big. 一旦应用程序变得复杂和庞大,这个小细节可以拯救您。

The advantage of using the method init to declare all injected variables is to have a clean looking code which is easy maintainable since everything injected is at this one location. 使用init方法声明所有注入变量的优点是具有干净的代码,易于维护,因为所有注入的都在这一个位置。 But that's actually preference :) 但这实际上是偏好:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM