Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Butterknife View injection

I stumbled across a very interesting Dependency Injection library called ButterKnife. Using ButterKnife it's easily possible to inject Views into activities or fragments.

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...
  }
}

However if using Dependency Injection those Views must be public so that Butterknife can inject it (using private fields results in an exception fields must not be private or static).

In my past project I always made all the member fields (including the views) private as I thought this is best practice (information hiding etc.) Now I am wondering if there is a reason why one should not make all the views public? In this case I cannot use ButterKnife but I want to use it because it simplifies the code a lot.

like image 549
Moonlit Avatar asked Dec 02 '14 08:12

Moonlit


People also ask

What is ButterKnife dependency injection?

Android ButterKnife library is a view injection library that injects views into android activity / fragments using annotations. For example, @BindView annotation avoids using findViewById()method by automatically type casting the view element. It has been developed by. Jake Wharton.


1 Answers

First off, Butter Knife is not a dependency injection library. You can think of it as a boilerplate reduction library since all it does is replace findViewById and various setXxxListener calls.

The reason that Butter Knife requires views not be private is that is actually generates code which sets the fields. The code that it generates lives in the same package as your class which is why the field must be package-private, protected, or public. If the field was private the generated code would fail to compile since it cannot access the private field.

The generated code looks something like this:

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);
}

When you call ButterKnife.inject(this) it looks up this generate class and calls the inject method with your instance of ExampleActivity as both the destination for the fields and the source for findViewById calls.

like image 144
Jake Wharton Avatar answered Oct 11 '22 18:10

Jake Wharton