Android: findViewById Fonksiyonu Yerine Alternatif Çözüm

Bilindiği üzere deklaratif yöntemle tasarlanan ekranlarda kullanılan GUI elemanlarının programatik nesnelere dönüştürülmesi amacıyla findViewByID() isimli fonksiyon (metot) kullanılmaktadır. Bu fonksiyon kullanılarak yapılan işlem, özellikle XCode ya da Visual Studio gibi güçlü RAD (Rapid Application Development) özelliklerine sahip araçları kullanan programcılar tarafından sıkça eleştirilmektedir. Her ne kadar bu işlemi kolaylaştırmaya yönelik sonradan birtakım üçüncü parti eklentiler (ButterKnife) gibi tasarlanmış ise de (yazar da dahil olmak üzere) bu araçlar geniş kitleler tarafından kabul görmemiştir.

Bu noktada daha özgün bir çözüm kullanmak isteyen okurlar için reflection ve annotation’lara dayalı olan yöntem tercih edilebilir.

Dikkat: Annotation konusuna yabancı ya da kendisini bu konuda yetersiz hisseden okurlar öncelikle ek bölümdeki annotation’ların anlatıldığı kısmı okumalıdırlar.   

Sözgelimi aşağıdaki gibi bir XML kodu ile deklaratif olarak tasarlanmış bir ekrandaki GUI elemanlarını ele almak gerekirse:

<LinearLayout android:id=”@+id/pnl” >

    <TextView android:id=“@+id/txt”

        android:text=“TeknolojiDergisi.net” … />

    <Button android:id=“@+id/btn”

        android:text=“TEST” … />

</LinearLayout>

Buradaki (pnl, btn, txt) id’li GUI elemanları için nesne yaratılmak istenildiğinde normalde aşağıdaki gibi bir kod satırı yazılmaktadır:

TextView txt = (TextView) findViewById(R.id.txt);

Oysa bu kod aşağıdaki şekle indirgenebilir:

@GUI(R.id.txt)

private TextView txt;

Burada kullanılmış olan @GUI annotation’ı aşağıdaki gibi tasarlanmıştır:

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface GUI

{

    int value() default 1;

}

@Target ve @Retention ise yine birer annotation olup, sırasıyla @GUI annotation’ının sadece sınıfın field’ları yani veri elemanları üzerinde kullanılabileceğini diğeri ise çalışma zamanında ele alınacağını anlatmaktadır.  

@GUI isimli annotation’ının kullanıldığı bir veri elemanının yaşayan bir nesne haline getirilmesini ise GuiUtil isimli sınıfın FindElements() isimli statik fonksiyonu -reflection mekanizması- yoluyla yapmaktadır.   

public class GuiUtil

{

    public static void FindElements(Activity activity)

    {

        try

        {

            for (Field f : activity.getClass().getDeclaredFields())

            {

                GUI gui = f.getAnnotation(GUI.class);

                if (gui != null)

                {

                    f.setAccessible(true);

                    f.set(activity, activity.findViewById(gui.value()));

                }

            }

        }

        catch (Exception ex)

        {

            Log.e(“err”, ex.getMessage());

        }

    }

}

Görüldüğü gibi FindElements() fonksiyonu, parametresine aldığı Activity nesnesinin, üzerinde @GUI annotation’ının kullanılmış olduğu veri elemanlarını dinamik olarak elde etmekte ve bunları içsel olarak yine findViewById() fonksiyonunu kullanarak nesne haline getirmektedir. Bu noktada yöntemin kullanışlı ve efektif olup olmadığı okuyucunun takdirine bırakılmıştır. Son kertede bu mekanizmanın Activity içerisindeki kullanımına bir örnek aşağıda verilmiştir:

public class MainActivity extends AppCompatActivity

{

    @GUI(R.id.pnl)

    private LinearLayout pnl;

    @GUI(R.id.btn)

    private Button btn;

    @GUI(R.id.txt)

    private TextView txt;

    private void btn_Click()

    {

        btn.setOnClickListener(

                new View.OnClickListener() {

                    @Override

                    public void onClick(View view) {

                        pnl.setBackgroundColor(Color.BLUE);

                        txt.setText(“SiberNext.com”);

                    }

                }

        );

    }

    @Override

    protected void onCreate(Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        GuiUtil.FindElements(this);

        btn_Click();

    }

}

Reklamlar

Swift4 type() fonksiyonu ile dinamik türün öğrenilmesi

Yakında çıkacak olan #Swift kitabımdan küçük alıntılara devam:

Swift’te bir nesnenin dinamik tür ismini öğrenmek için geçmiş versiyonlarda dynamicType kullanılmaktaydı ancak yeni versiyonda bu işlem için artık type() isimli fonksiyon kullanılmaktadır.

Bu fonksiyonun parametre etiket isminin “of” olması okuyucunun aklını karıştırıp, C türevi dillerdeki typeof() operatörününün Swift’te olduğu izlenimini uyandırmamalıdır. “obj” bir nesne örneği olmak üzere:

print(obj.dynamicType) // yerine
print(type(of: obj)) // kullanılmalıdır

Şüphesiz aynı işlem gerektiğinde self için de yapılabilir.

Swift Protocol Composition

Birden fazla protokol ile birleştirilmiş referanslar bildirilebilir. Bu durumda o referansa ancak o bildirimde belirtilen protokollerin hepsini destekleyen bir sınıf, yapı ya da enum değişkeni atanabilir.

Bildirimde protokol birleştirme işlemi protokol isimlerinin arasına “&” sembolü konularak yapılır. Örneğin:

protocol Protokol1

{

func Foo()

}

protocol Protokol2

{

func Bar()

}

class CSample1 : Protokol1

{

func Foo()

{

print(“foo”)

}

}

class CSample2 : Protokol1, Protokol2

{

func Foo()

{

print(“foo”)

}

func Bar()

{

print(“bar”)

}

}

/////////////TEST//////////////

func Test(prm: Protokol1 & Protokol2)

{

prm.Foo()

prm.Bar()

}

// Test(prm: CSample1())

// Argument type CSample1 doesnt conform to expected type ‘…’

Test(prm: CSample2()) // OK

Şüphesiz protokol listesinde sırasının bir önemi yoktur. Örneğin:

let p1: Protokol1 & Protokol2 = CSample2()

let p2: Protokol2 & Protokol1 = p1       // geçerli