Butter Knife 라이브러리 사용법
25 Mar 2017 | Android UX Open Source안드로이드 GUI 개발을 하다보면, 가장 귀찮은 것 중 하나가 화면에 컴포넌트를 하나 추가하는 것입니다.
예를 들어 화면에 버튼을 추가한다고 하면 다음과 같은 작업들을 거쳐야 합니다.
- XML Layout에 버튼을 추가한다.
- 해당 Activity(Fragment)에서 그 컴포넌트에 해당하는 변수를 추가한다. ex) private Button button;
- findViewById를 통해 그 컴포넌트를 변수에 할당한다. ex) button = (Button)findViewById(R.id.button)
- 그 버튼에 setOnClickListener를 통해 이벤트를 등록한다.
컴포넌트가 몇 개 안 될 경우는 큰 문제가 안되는데, 컴포넌트가 많아질수록 위 코드들은 감당이 안 될 정도로 많아지고 복잡해집니다. 이럴 때 ‘Butter Knife’ 라이브러리를 사용하면 코드량이 상당히 줄어듭니다. (사실, 이런 식으로 별거 아닌 코드를 Wrapping 하는 외부 라이브러리를 쓰는 걸 선호하진 않지만 Butter Knife는 생각보다 괜찮은 것 같아서 최근에 조금씩 사용을 해보고 있습니다.)
간단한 예제 코드로 알아보도록 하겠습니다. 더 자세한 내용은 공식 홈페이지를 참조하시면 됩니다. 버전에 따라 문법이 조금씩 바뀌고 있는데, 여기서는 현재 최신 버전인 8.5.1 기준으로 사용해보겠습니다.
gradle 세팅
dependencies {
    ...
    compile 'com.jakewharton:butterknife:8.5.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
    ...
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/activity_main"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:orientation="vertical"
  tools:context="com.snowdeer.butterknife.sample.MainActivity">
  <TextView
    android:id="@+id/title"
    android:textStyle="bold"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Title"
    android:textSize="32sp" />
  <Button
    android:id="@+id/button"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Click Me!" />
  <ImageView
    android:id="@+id/imageview"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</LinearLayout>
strings.xml
<resources> <string name="app_name">ButterKnifeSample</string> <string name="title">Hello. Butter Knife</string> </resources>
MainActivity.java
여기서 가장 중요한 부분은 onCreate() 함수 내의 다음 코드입니다.
ButterKnife.bind(this);
위 코드를 호출해주어야 각 View들이 바인딩(Binding)이 됩니다.
import android.graphics.drawable.Drawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.BindDrawable;
import butterknife.BindString;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity {
  @BindView(R.id.title)
  TextView titleView;
  @BindView(R.id.imageview)
  ImageView imageView;
  @BindString(R.string.title)
  String title;
  @BindDrawable(R.mipmap.ic_launcher)
  Drawable drawable;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ButterKnife.bind(this);
  }
  @OnClick(R.id.button)
  void onButtonClicked() {
    titleView.setText(title);
    imageView.setImageDrawable(drawable);
  }
  ;
}
Fragment 에서의 예제
public class FancyFragment extends Fragment {
  @BindView(R.id.button1)
  Button button1;
  @BindView(R.id.button2)
  Button button2;
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fancy_fragment, container, false);
    ButterKnife.bind(this, view);
    // TODO Use fields...
    return view;
  }
}
ListView 등에서 사용하는 Adapter 및 ViewHolder 예제
public class MyAdapter extends BaseAdapter {
  @Override
  public View getView(int position, View view, ViewGroup parent) {
    ViewHolder holder;
    if(view != null) {
      holder = (ViewHolder) view.getTag();
    } else {
      view = inflater.inflate(R.layout.whatever, parent, false);
      holder = new ViewHolder(view);
      view.setTag(holder);
    }
    holder.name.setText("John Doe");
    // etc...
    return view;
  }
  static class ViewHolder {
    @BindView(R.id.title)
    TextView name;
    @BindView(R.id.job_title)
    TextView jobTitle;
    public ViewHolder(View view) {
      ButterKnife.bind(this, view);
    }
  }
}
이벤트 등록 예제
@OnClick(R.id.submit)
public void submit(View view) {
  // TODO submit data to server...
}
@OnClick(R.id.submit)
public void submit() {
  // TODO submit data to server...
}
@OnClick(R.id.submit)
public void sayHi(Button button) {
  button.setText("Hello!");
}
@OnClick({R.id.door1, R.id.door2, R.id.door3})
public void pickDoor(DoorView door) {
  if(door.hasPrizeBehind()) {
    Toast.makeText(this, "You win!", LENGTH_SHORT).show();
  } else {
    Toast.makeText(this, "Try again", LENGTH_SHORT).show();
  }
}
  