web-dev-qa-db-ja.com

バターナイフビューインジェクション

ButterKnifeと呼ばれる非常に興味深い依存性注入ライブラリに出くわしました。 ButterKnifeを使用すると、ビューをアクティビティまたはフラグメントに簡単に挿入できます。

class ExampleActivity extends Activity {
  @InjectView(R.id.title) TextView title;
  @InjectView(R.id.subtitle) TextView subtitle;
  @InjectView(R.id.footer) TextView footer;

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    ButterKnife.inject(this);
    // TODO Use "injected" views...
  }
}

ただし、依存性注入を使用する場合は、publicが注入できるようにこれらのビューをButterknifeにする必要があります(privateフィールドを使用すると例外fields must not be private or static)。

私の過去のプロジェクトでは、これがベストプラクティス(情報隠蔽など)だと思っていたので、常にすべてのメンバーフィールド(ビューを含む)をprivateにしました。今、すべてを作成しない理由があるかどうか疑問に思っています。ビューpublic?この場合、ButterKnifeは使用できませんが、コードが大幅に簡略化されるため、使用したいと思います。

22
Moonlit

まず、ButterKnifeは依存性注入ライブラリではありません。 findViewByIdとさまざまなsetXxxListener呼び出しを置き換えるだけなので、定型的な削減ライブラリと考えることができます。

バターナイフがプライベートではないビューを必要とする理由は、実際にはフィールドを設定するコードを生成するためです。生成されるコードはクラスと同じパッケージに存在するため、フィールドはpackage-private、protected、またはpublicである必要があります。フィールドがプライベートの場合、生成されたコードはプライベートフィールドにアクセスできないため、コンパイルに失敗します。

生成されたコードは次のようになります。

_public static void inject(ExampleActivity target, ExampleActivity source) {
  target.title = (TextView) source.findViewById(R.id.title);
  target.subtitle = (TextView) source.findViewById(R.id.subtitle);
  target.footer = (TextView) source.findViewById(R.id.footer);
}
_

ButterKnife.inject(this)を呼び出すと、この生成クラスが検索され、injectのインスタンスをフィールドの宛先とExampleActivity呼び出しのソースの両方として使用してfindViewByIdメソッドが呼び出されます。

44
Jake Wharton