[Android] View에 대한 Bind를 간단하게 해주는 Butter Knife

v 8.6.0 기준으로 소개 됩니다.

공식 페이지 : http://jakewharton.github.io/butterknife/
한줄 소개 : Field, Resource, Event Callback을 Android View 에 Bind 하기 위한 Annotation을 제공한다.
예제 코드 : http://github.com/LonelyWolfLee/lw-butterknife-example/
라이센스 : the Apache License, Version 2.0

Introduction

Simple example

TextView title에 R.id.title을 할당하기 위해서 기존에는 아래와 같이 하였다.
TextView title;
...
@Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    title = (TextView)activity.findViewById(R.id.title);
    // TODO Use fields...
}

하지만 Butter Knife를 사용하면 아래와 같이 사용이 가능 하다.
@BindView(R.id.title) TextView title;
...
@Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.simple_activity);
    ButterKnife.bind(this);
    // TODO Use fields...
}

Advantage

  • control 객체를 가져오거나 resource 등을 가져오는 방식을 일관된 방식으로 사용 할 수 있다
  • 불필요한 boilerplate를 제거 할 수 있다
  • 로직과 정의 및 선언부를 분리 할 수 있어서 로직 구현 및 분석에 용이하다.

Installation

참고 : http://jakewharton.github.io/butterknife/#download

Android의 개발 환경은 IntelliJ 기반의 Android Studio에 gradle 기반의 프로젝트 설정 방식을 사용 한다. 원하는 프로젝트의 gradle 파일로 가서 다음과 같은 dependency 항목을 추가 한다. (실제 버전 확인)
dependencies {
    ...
    compile 'com.jakewharton:butterknife:8.6.0'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0'
}
정상적으로 동작 하지 않을 경우 다음 설정이 되어있는지 확인한다.
File > Other Settings > Default Settings > Build, Execution, Deployment > Compiler > Annotation Processors 에서 "Enable annotation processing"를 체크해준다.

Usages with example

Basic usage (예제 코드)

Controls, resources, event callback 을 annotation을 사용하여 정의 하고, onCreate()에서 ButterKnife.bind(this); 를 호출한다.
public class BasicWithButterKnifeActivity extends AppCompatActivity {

    @BindView(R.id.text_change_view)
    TextView changeView;

    @BindString(R.string.str_basic)
    String strChanged;

    @BindColor(R.color.colorBasicChanged)
    int colorChanged;

    @OnClick(R.id.button_change_text)
    void changeText() {
        changeView.setText(strChanged);
    }

    @OnClick(R.id.button_change_color)
    void changeColor() {
        changeView.setBackgroundColor(colorChanged);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_basic);

        ButterKnife.bind(this);
    }
}

Usage on ViewHolder (예제 코드)

Controls, resources, event callback 을 annotation을 사용하여 정의 하고, constructor에서 ButterKnife.bind(Object, View); 를 호출한다.
예제에서 @OnClick 함수 내부에 item을 가져오기 위해 getItem을 사용하였다. clickButton()은 보기에는 method 정의로 보이지만 실제로는 R.id.btn_item 로 선언 된 Button view에 setOnClickListener 를 사용하여 달아준 리스너 객체와 연결되어 있다. 그렇기 떄문에 내부에서 getItem이 아닌 this.item 식으로 사용하게 되면 처음 class 가 생성 될 때에 ButterKnife.bind() 가 호출 될 시점의 값인 null 이 계속 호출 된다. 그래서 getItem() 같이 함수로 연결하여 나중에 들어온 값을 가져 올수 있도록 해야한다.
class RecyclerWithButterKnifeViewHolder extends RecyclerView.ViewHolder {
    @BindView(R.id.txt_item)
    TextView text;
    String item;

    RecyclerWithButterKnifeViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }

    void bind(final String item) {
        this.item = item;
    }

    @OnClick(R.id.btn_item)
    void clickButton() {
        text.setText(getItem());
    }

    private String getItem() {
        return this.item;
    }
}

Usage on Fragment (예제 코드)

Controls, resources, event callback 을 annotation을 사용하여 정의 하고, constructor에서 ButterKnife.bind(Object, View); 를 호출한다.
Fragment는 실제로 사용되는 Activity와 lifecycle이 다르기 때문에 적절한 위치에서 bind 된 객체를 null로 만들어줄 필요가 있다. 이를 위해 bind 시점에 Unbinder 를 반환하여 handling 할수 있게 해준다. onCreateView 에서 bind 해고 onDestroyView에서 unbind 하는 것이 일반적이다.
public class FragmentB extends Fragment {

    @BindView(R.id.txt_description)
    TextView description;
    @BindView(R.id.img_view)
    ImageView image;
    @BindString(R.string.str_frag_b)
    String strDescription;
    @BindDrawable(android.R.drawable.star_big_on)
    Drawable drawable;

    private Unbinder unbinder;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.layout_fragment, container, false);

        unbinder = ButterKnife.bind(this, view);
        description.setText(strDescription);
        image.setImageDrawable(drawable);

        return view;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }
}

공식 페이지에서 더 많은 사용 예제를 확인 할 수 있다.

댓글