[ANDROID] Butter Knife แล้วคุณจะลืมวิธี findViewById แบบเดิมๆ


          หากจะหา view ใน XML แล้วหละก็ เพื่อนๆ นักพัฒนา Android ก็คงจะนึกถึง findViewById กันเป็นอันดับแรก ซึ่งวันนี้ผมมีของดีมานำเสนออีกแล้วครับ ของดีที่ว่านั้นก็ คือ คือ คืออออออ Butter Knife  นั่นเอง ส่วนความสามารถของ library ตัวนี้จะมีอะไรบ้าง ก็ต้องตามมาอ่านดูในบทความนะครับ
Update : Butter Knife มีการ update version จาก 6.x.x ไปเป็น 7.x.x ซึ่งมีการเปลี่ยน API บางส่วน เลยขออนุญาตแก้ไขบทความนะครับ

การเปลี่ยนแปลงหลักๆ  จาก 6.x.x ไป 7.x.x

@InjectView(View ID) -> @Bind(View ID)
ButterKnife.inject(this); -> ButterKnife.bind(this);
ดู Change log เพิ่มเติม ที่นี่

การติดตั้ง

ก็เช่นเคย ที่ build.gradle ครับ
compile 'com.jakewharton:butterknife:7.0.1'

การใช้งานเบื้องต้น

เพื่อให้เห็นภาพ เรามาดูการเปรียบเทียบกับวิธีการแบบเดิมกันก่อนดีกว่า
วิธีดั้งเดิมใช้มาตั้งแต่สมัยบรรพบุรุษ ด้วย findViewById
class ExampleActivity extends Activity {
  private Button myButton;
  private TextView myTextView1;
  private TextView myTextView2;
  private TextView myTextView3;

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_layout);
    myButton = (Button) findViewById(R.id.my_button);
    myTextView1 = (TextView) findViewById(R.id.my_textview1);
    myTextView2 = (TextView) findViewById(R.id.my_textview2);
    myTextView3 = (TextView) findViewById(R.id.my_textview3);
  }
}
ต่อไปมาดูของ Butter Knife ด้วย annotation @Bind
class ExampleActivity extends Activity {
  @Bind(R.id.my_button) Button myButton;
  @Bind(R.id.my_textview1) TextView myTextView1;
  @Bind(R.id.my_textview2) TextView myTextView2;
  @Bind(R.id.my_textview3) TextView myTextView3;

  @Override public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_layout);
    ButterKnife.bind(this); // บรรทัดต้องใส่ทุกครั้ง เพื่อเป็นการเริ่มการทำงานของ Butter Knife
  }
}
จากโค้ดทั้ง 2 ชุดด้านบนมีการทำงานเหมือนกัน คือ หา view ด้วย ID ใน res/layout/my_layout.xml นั่นเอง
พอเห็นความต่างไหมใช่ไหมครับ แล้วลองนึกภาพที่เรามี View เยอะๆ โค้ดแบบเดิมจะยาวกว่าซึ่งถ้าเราเปลี่ยนมาใช้ Butter Knife จะเห็นว่าโค้ดจะดูสะอาดตาขึ้น นอกจากนี้ยังลดความผิดพลาดเรื่องการ casting type ของ view ได้อีกด้วย

ใช้กับ Fragment ได้ด้วยนะ

public class ExampleFragment extends Fragment {
  @Bind(R.id.button1) Button button1;
  @Bind(R.id.button2) Button button2;

  @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.my_fragment, container, false);
    ButterKnife.bind(this, view);
    return view;
  }
}
ตรงนี้สังเกตุว่า parameter จะเปลี่ยนไปเล็กน้อยจากการใช้งานใน Activity นะครับ
Activity :  ButterKnife.bind(this);
Fragment :  ButterKnife.bind(this, view);

ยังไม่พอใช้กับ Adapter ก็ยังได้!!

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 {
    @Bind(R.id.title) TextView name;
    @Bind(R.id.job_title) TextView jobTitle;

    public ViewHolder(View view) {
      ButterKnife.bind(this, view);
    }
  }
}

เล่นกับ Event ก็ยังได้

@OnClick
@OnClick(R.id.submit)
public void submit(View view) {
  ...
}
@OnCheckedChange
@OnCheckedChange(R.id.radio)
public void checkedChanged(boolean checked) {
  ...
}
การใช้งานทั่วๆ ไปก็จะใช้งานประมาณนี้ แต่ก็ยังมีความสามารถอื่นๆ โดยสามารถเข้าไปดูได้ที่ลิงค์อ้างอิงเพิ่มเติมได้เลยครับ

         สรุปแล้วโดยส่วนตัวผมค่อนข้างชอบ Butter Knife นะครับ เพราะใช้แล้วรู้สึกว่าโค้ดดูสะอาดขึ้นมาอีกนิดนึง แล้วก็ยังช่วยตัดปัญหาเรื่อง casting type ของ view ไปได้อีกหน่อยนึง สำหรับใครที่ยังไม่ได้ลองว่างๆ ก็ลองหาโอกาสเล่นดูนะครับ
"ไม่ต้องเชื่อผมก็ได้ แต่ผมอยากให้คุณเปิดใจ :)"

ข้อพึงระวัง

         หากโปรเจคมีการแยก Module ออกมาหลายๆ Module จะสามารถเรียกใช้งาน Butter Knife ได้บน Main Module เท่านั้น เนื่องจากเป็นข้อจำกัดของ Java's annotations และ Android SDK.
(อ้างอิงจาก : github.com)
ขอบคุณ คุณเอกสุดหล่อ ที่แจ้งเข้ามานะครับ

ลิงค์อ้างอิง

View injection library : Butter Knife

Teeranai.P

Developer ตัวน้อยๆ ที่หลงใหลในโลกของการพัฒนา Software. รักการเขียนโปรแกรมเป็นอันดับ 2 รองลงมาจากการนอน