ButterKnife Nasıl Çalışır?

Bu yazımızda, bir View Injector kütüphanesi olan ButterKnife’ın nasıl çalıştığını inceleyeceğiz.

Square‘da çalışan Jake Wharton son dönemde geliştirdiği kütüphanelerle Android dünyasının adeta zirvesine yerleşti. ActionbarSherlock, Picasso, Retrofit ve ButterKnife gibi kütüphaneler, yazılım geliştiricilerin hayatını epey kolaylaştırıyor. Bundan dolayı Jake Wharton’a “Android’in Taçsız Prensi” diyebiliriz. Bu yazımızda, bir View Injector kütüphanesi olan ButterKnife’in nasıl çalıştığını inceleyeceğiz.

 

Öncesi – sonrası

Bilindiği üzere ButterKnife bir View Injector kütüphanesidir. Bir başka deyişle, önyüzde tanımladığımız view bileşenlerini, annotation’lar kullanarak projemize dâhil etmemize olanak sağlıyor. Sadece view’leri değil, aynı zamanda projemizde kullandığımız String, Drawable, Color ve Dimen gibi kaynakları da aynı yöntemle pratik bir şekilde projemize ekleyip bizi kod tekrarı yapmaktan kurtarıyor.

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

    @Override public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.simple_activity);
        ButterKnife.bind(this);
        // TODO Use fields...
    }
}

Görüldüğü üzere findViewById() metodunu tekrar tekrar kullanmak zorunda kalmıyoruz. Peki, ButterKnife’ın çalışma prensibi nedir?

 

Ne sihirdir ne keramet! Annotation Processing’de alamet!

ButterKnife’ın arkasında yatan güç, Annotation Processing’dir. Annotation Processing, derleme işleminin aşamalarından biridir. JDK’nın belgesine göz atarsanız, derleme sürecini anlatan bölümde bunu açıkça görebilirsiniz. (OpenJDK Belgesi)

Annotationlar derleme zamanında tespit edilir ve normal kod satırlarına çevrilirler. Bir başka deyişle, runtime dediğimiz gerçek çalışma zamanında annotation diye bir şey yoktur. Projemizi derlediğimizde, Annotation Processor devreye girer, projedeki tüm Java sınıflarını tarayıp, annotationları bulur ve normal kod satırlarına çevirir. Üretilen bu yeni kod, normal bir Java sınıfı gibi yeniden derlenir. Annotationlar sadece yazılım geliştirme sürecini kolaylaştırmak için görünürde vardır, derleme zamanının ötesine geçemezler. Unutulmamalıdır ki, Annotation Processorlar sadece annotationları normal satırlara çevirmeye yarar. Derleme anında, sınıflara yeni metodlar eklemek gibi değişiklikler yapamazlar.

Java’da kendi annotationlarımızı yazma olanağımız var. Bunun için aynı zamanda bu annotationları işleyecek bir Annotation Processor yazmamız gerekli. ButterKnife için yapılan da tam olarak bundan ibaret. Bir Annotation Processor yazmak için AbstractProcessor.java sınıfını extend eden bir sınıf yazmamız gereklidir. AbstractProcessor.java içinde tanımlı olan ve bizim kullanacağımız process() sınıfı, asıl işin yapıldığı yer.

Bu bağlantıya tıklayarak ButterKnife için yazılan ButterKnifeProcessor.java sınıfını inceleyebilirsiniz.

 

ButterKnight algoritması

Android projenizi ButterKnife kullanarak yazdınız ve Build düğmesine basıp, projeyi derlediniz. Arka planda olanlar kabaca şu şekilde:

  • Derleyici, ButterKnife’in annotation processorunun process() metodunu çağırır.
  • Bu metot içinde, projenizdeki tüm Java sınıfları taranır ve ButterKnife annotationları nerelerde kullanılmış, tespit edilir.
  • Annotation kullanılmış bir sınıf bulunduğu zaman, yeni bir Java dosyası üretilir: <Sınıf_Adi>$$ViewInjector.java (Bildiğimiz bir Java sınıfı)
  • Bu yeni ViewInjector sınıfı içindeki annotationlar, bizim bildiğimiz eski stil kodlarla yer değiştirilir. Kısacası, findViewById() ve view.setOnClickListener() gibi satırlar tam bu noktada projemize eklenir.
  • Son olarak da ButterKnife.inject(this) satırı çağırıldığında, üretilen tüm VievInjector dosyalarının inject() metotları çağrılır ve bu dosyalar derlenmeye başlanır.

Yukarıdaki verdiğimiz kod derlenirken, ButterKnife tarafından üretilen kodu aşağıda görebiliyoruz:

public class ExampleActivity$$ViewBinder<T extends com.lgvalle.samples.ui.ExampleActivity> implements ViewBinder<T> {
    @Override public void bind(final Finder finder, final T target, Object source) {
        View view;
        view = finder.findRequiredView(source, 21313618, “field ‘title’”);
        target.title = finder.castView(view, 21313618, “field ‘title’”);
        view = finder.findRequiredView(source, 21313618, “field ‘subtitle’”);
        target.subtitle = finder.castView(view, 21313618, “field ‘subtitle’”);
    }

Son olarak tekrar belirtelim; siz de kendi annotationlarınızı geliştirebilir ve ButterKnife gibi bir View Injector kütuphanesi yazabilirsiniz. ButterKnife hakkında daha fazla bilgi ve kaynak kodları için aşağıdaki bağlantıyı inceleyebilirsiniz:

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s