Jetpack Compose’a Giriş

Oguz Şahin
Huawei Developers - Türkiye
8 min readOct 21, 2021

Bir Android uygulamanın temel yapıtaşlarından biri de hiç şüphesiz ki tasarım kısmı. Hatta kullanıcılara iyi bir arayüz sunmak, kullanıcı deneyimini iyi bir şekilde arttırdığı gibi ürününüzün tercih edilmesi konusunda da çok hayati bir rol oynuyor. Son günlerde de Android tarafında, release versiyonu yayınlandıktan bu yana oldukça popüler bir şekilde yer tutan Jetpack Compose, Android uygulama ekosisteminde developerların var olan tasarımı kodlamasında yeni bir yaklaşım ve soluk getiriyor.

Bu yazıda kimi developerların heyecanlı şekilde kimilerininse endişeli bir şekilde beklediği Jetpack Compose’dan bahsedeceğim. Yazının içeriği Jetpack Compose dünyasına sağlam bir şekilde merhaba demenize ve Compose dünyasını keşfetmeye fazlasıyla yardımcı olacağını düşündüğüm bir şekilde ilerleyecek. Şimdiden keyifli okumalar :)

Neden Android Toolkit Takımı Jetpack Compose gibi bir toola ihtiyaç duydu?

Öncelikle her yeni teknolojinin muhakkak ki bir şekilde eskisinin üzerine koyması ve bununla birlikte eski yaklaşımdaki bazı sorunlara çözüm bulması gerek. Bu durumu anlamak belki de yeni teknolojiyi öğrenme de en önemli adımlardan biri diyebilirim kendi adıma. Bundan dolayı Jetpack Compose dünyasında kürek çekmeye başlamadan önce hali hazırda view based design sisteminin(xml ile ui oluşturma yaklaşımı), ui tasarlarken biz android developerlara çıkardığı sıkıntılara bakalım.

Aynı zamanda jetpack compose gibi bir tool’a android takımı neden ihtiyaç duydu, onu da iyice anlayalım. Ek olarak linkteki videodan da android toolkit takımının sunumunu izleyerek de ilk ağızdan derinlemesine bir bakış yapabilirsiniz.

View.java Sınıfının Kod Sayısı

1-) Bu noktada ilk sorunlardan birine bakacak olursak, yukarıdaki ekte de görüleceği üzere View.java sınıfının 30.000 satır gibi korkunç bir rakama yaklaşması. Hepimizin bildiği gibi her view’ın başlıca kalıtıldığı sınıf View.java sınıfı. Android toolkit takımı bu sınıfın ulaştığı kod sayısının artık yönetilemez bir hale geldiğini belirterek ilk sorun olarak buna çözüm aramak istediklerini belirtiyorlar.

View Kalıtım Şablonu

2-) Bir diğer sorun olarak da garip bir kalıtılma yapısı olduğunu belirtiyorlar. Yukarıdaki resimde de görüldüğü üzere, view based design sisteminin bir soyutlama üzerine kurulduğunu hali hazırda biliyoruz. Buradan yola çıkarak, Button sınıfının TextView sınıfından kalıtım aldığı örneğini göz önünde bulundurarak ilerlersek, bu yapılan soyutlama ile beraber Button textinin seçilebilir ve düzenlenebilir gibi özellikler alması gibi durumlar oluşuyor. Button’un bu özellikleri taşıması çok da doğru davranışlar olmayacaktır. Buradaki garip kalıtım yapısının oluşturduğu durumu Jetpack Compose’u geliştirme sürecinde göz önünde bulundurduklarını ifade ediyorlar.

3-) Bir sayfayı view based design yaklaşımıyla kodlarken genelde bir xml layout kodlayıp, bununla birlikte viewlar için çeşitli ortak davranışları styles.xml etrafında toplayıp, custom view gibi yapılar oluştururken de attiributelarımızı attrs.xml sınıfına koyup, son olarak da ui lojiğimizi bir activity veyahut fragment (.kt veya .java) uzantılı dosyasında yazıyoruz. Bu yaklaşım bize ister istemez çokça kod satırı yazmamıza sebep oluyor. Ayrıca bu kodlamayı yaparken de iki farklı dil kullanıyoruz(java|kotlin & xml). Bu durum da, android toolkit takımının değiştirmek ve geliştirmek istediği sorunlardan biri haline gelmiş.

Spinner Sınıfı

4-) Diyelim ki tasarımını kodlayacağımız sayfa bir seçim işlemi içeriyor olsun. Bunun için genelde kullandığımız view ise Spinner oluyor. Fakat bu view sınıfı için kullanılan isimlendirme(diğer plartformlarda da) Dropdown veya ComboBox olması daha doğru olduğu aşikar. Buradan şuan ki kullandığımız isimlendirmenin saçma ve eski bir adlandırma olduğunu dile getiriyor Romain Guy. Ayrıca neden daha önce spinner diye adlandırıldığını paylaştığım linkteki sunumda bahsediyor. İsterseniz izleyerek bu konuda bilgi sahibi olabilirsiniz.

5-) Bir diğer durumda , imperative ui (daha sonra bundan detaylı bahsedeceğiz) yaklaşımının doğurduğu sıkıntıdan kaynaklanan Source Of Truth olayı. Imperative ui yaklaşımında; bir layout inflate ederiz, daha sonrasında içerisindeki componentlere çeşitli yönemlerle erişir (findViewById, viewbindig, databinding vb.) ve erişilen viewların internal statelerini değiştirerek ekranda görünen durumu sağlamış oluruz. Burada kastedilen state değiştirme olaylarına örnek verecek olursak visibility değiştirme(gone,visible gibi), TextView’a text set etme vb. gibi örnekler verilebilir.

Bir checkbox örneğinden gidersek, kullanıcı checkleme işlemini yaptığında view’ın internal durumu değişip ekranda checkleme işlemi gerçekleşir, genelde bu değişikliği checkChangedListener ile dinleriz ve biz de ona göre tutuğumuz bir değişkeni değiştiririz veya buna göre yapacağımız işi tetikleriz(örneğin backende bir istek atmak gibi). Bu noktada sağlamak istediğimiz şey checkboxın içerisinde tuttuğu state ile bizim tuttuğumuz state’in eş zamanlı gitmesi. Fakat listener’ın tetiklenme olayı sadece kullanıcı tarafından değil bizim kod tarafından da yapacağımız bir işlem olabiliyor. Bu da halihazırda tek bir kaynaktan gitmediği için bazı durumlarda bizi ektra ve gereksiz bir kod yazma durumuna sokabiliyor.

Jetpack Compose’u Tanıyalım

Kısaca tanımını yapacak olursak; Jetpack Compose native android uiları oluşturmamızı sağlayan modern bir toolkit. Jetpack Compose, tamamen Kotlin ile yazıldı ve bize tek bir dille, daha az kod satırı yazarak, daha hızlı, daha basit bir geliştirme yapmayı sunuyor. Ayrıca android studio ve diğer jetpack öğeleri ile destekle de geliyor. Böylece geliştirme hızımız da fazlasıyla arttırmış oluyor. Jetpack Compose declaritive ui yaklaşımı sunar. Bu yaklaşımı da kısaca dataya göre çizilen ui olarak düşünebilirsiniz şimdilik(Daha sonrasında detayını gireceğiz). Bu da bize single bir source üzerinden geliştirme yapma güzelliği sunuyor. Jetpack Compose’un sunduğu faydaları ve bu geçişi sağlamış tanınmış takımların(Twitter,Square,Cuvva,Monzo) görüşlerini bu linkten de inceleyebilirisiniz.

Bir projeye yeni bir tool eklemek projenizin apk boyutunu ve build sürelerini de etkileyecektir. Jetpack compose ile buradaki değişiklikleri değerlendirmekte ve incelemekte yarar var.

Jetpack Compose Apk Boyutu Karşılaştırması

Yukarıdaki resmin sol tarafında Tivi uygulamasının view based designdan tamamen jetpack compose ile refactor edilmesinden sonra apk boyutundaki değişimi gösteren grafiği görüyoruz. Bu geçiş sonrası apk boyutunda %49 (4.49 mb iken compose ile birlikte 2.39 mb olmuş), method sayısında %17, xml ile yazılan kod sayında ise %76 azalma olmuş. Sağ tarafta ise view based design ve jetpack composeun beraber kullanıldığı Sunflower uygulamasının grafiğini görüyoruz. Beraber kullanıldığında 2407 KB’dan 2982 KB’a çıkarak 575KB gibi bir artış göstermiş.

Jetpack Compose Build Süresi Karşılaştırması

Build sürelerindeki değişimlere bakacak olursak, Tivi uygulamasının refactor edilmeden önceki build süresi 108.71saniyeymiş. Refactor edildikten sonra 76.96 saniyeye düşerek %29 gibi bir azalma olmuş. Bu azalışı en çok etkileyen durum ise Data binding ve Epoxy kütüphanelerinin projeden çıkarılması olmuş. Bu iki kütaphanenin bu kadar etkide bulunma sebebi ise kapt annotation processor’u kullanması.(build esnasında kod ürettiklerinden build süresini arttırırlar). Sunflower ise 11.57 saniyeden 12.45 saniyeye çıkarak %7.6 artış göstermiş.

Jetpack Compose’un bize build süresi ve apk boyutu olarak da ergonomi sağladığını görüyoruz.(Ayrıca linkten de inceleyebilirsiniz.)

Jetpack Compose’ u daha iyi anlamak ve geliştirmek için biraz da declarative ve imperative ui yaklaşımına bakmakta yarar var. Bir yandan Jetpack Compose yapısını daha iyi anlamamıza ve kavramamıza olanak sağlarken diğer yandan da eski ve yeni yaklaşımların kıyasına bakmak, yeni teknolojiyi anlamak ve özümsemek için iyi olacaktır.

Imperative Ui

Imperative Ui

Imperative ui yaklaşımı, hali hazırda android geliştirme yaparken kullandığımız view based olan yaklaşım. Bu yaklaşımda yaptığımız şeyi kısaca özetlersek, ilk önce ayırdığımız bir xml layout içinde çeşitli viewlar koyarak tasarımımızı oluşturuyoruz. Daha sonra oluşturduğumuz layoutu render ederek(inflate işlemi), kullanıcının ekranda görmesini ve içinde bulunan viewlara etkileşimde bulunmasını sağlıyoruz. Bu viewlarda kendi içlerinde belli state bulunduruyorlar ve bu internal stateleri kullanıcının etkileşimine göre değiştirerek var olan uygulama davranışını sağlatıyoruz. Bu yaklaşımda daha çok ekranda ne görünmesi değil , nasıl görüneceği üzerinden bir yaklaşımla ilerliyoruz.

Declarative Ui

Declaritive Ui

Declarative ui yaklaşımı ise hali hazırda yazılım dünyasında gerek mobil gerek web geliştirirken kullanılan teknolojilerinde kullandığı yaklaşım. Kaldı ki Jetpack Compose’u geliştiren takım, bu teknolojilerden de ilham aldıklarını belirtiyorlar. Flutter, React Native, Litho, Vue Js bunlara örnek verilebilir. Bu yaklaşımda bu sefer de nasıl görünecek değil ne görünecek mantığıyla ilerliyoruz. Belli bir dataya göre ekranda neyi göstereceğiz gibi düşünebiliriz. Resimde görüldüğü üzere, kullanıcı tarafından bir etkileşim oluyor ve bu etkileşim sonunda sağlanan dataya göre gösterilecek ui çizim işlemini gerçekleştiriyoruz. Şunu da eklemek istiyorum, bu işlem state olayına göre sürekli gerçekleşiyor. Yani aslında bir nevi o component’i her seferinde baştan çizdiriyorsunuz ekrana.

Bu yaklaşımın iyi bir şekilde kavranması kendi adıma Jetpack Compose geliştirmeye başlarken en önemli kısımlardan oldu. Bu yüzden daha iyi anlaşılması için bir örnek vermek istiyorum. Farz edelim ki, ekranda kullanıcıdan bir text girdisi alacağız ve her karakter girişi gerçekleştirildğinde girilen texti butonun altında göstereceğiz. Bu noktada kullanıcının texti girerken girdiği her karakter için yeniden çizim işlemi gerçekleşeğini söyleyebiliriz. İşleyiş mantığı da şöyle olacak; siz her karakter girdiğinizde observable bir yapıyla componentleri yeniden çizdireceksiniz (recomposition olayı) ve her girilen karakter ile birlikte hem girdi aldığınız component(Edittext düşünülebilir)son text ile ekranda görünürken hem de text’te yeni değeriyle ekranda gösterilecek ve bu akış sürekli devam edecek bu şekilde. Componentlerdeki state mantığı compose ile birlikte daha stateless hal alıyor. Geliştirirken de olabildiğince stateless yapmak üzerine yoğunlaşacağız. Bunun sebeplerinden ve avantajlarından daha sonra bahsedeceğim.

Bu iki yaklaşımı da öğrendikten sonra, bir örnekle hem öğrendiklerimizi pekiştirelim hem de iki yaklaşım arasındaki farkları kıyaslayalım.

Örneğimiz okunmayan mail durumuna göre bir icon göstermek olsun. Eğer ki okunmamış herhangi bir mail yoksa boş bir zarf gösterelim. Okunmamış maillerimiz var ise bu zarfın içerisinde kağıt olsun ve aynı zamanda okunmamış mail sayısı 99 dan az ise okunmamış mail sayısını eğer fazla ise 99+ olarak bir badge gösterelim. Ayrıca eğer 99 dan fazla ise ateş iconu da ekleyerek iconumuzu gösterelim.

Imperative Yaklaşımla Kodlama

Eğer ki bunu imperative yaklaşımla kodluyor olsaydık, yukarıdaki resimde görüldüğü üzere çokça state değiştirme durumunu gözeterek kodlama yapacaktık. Update durumunda state değişikliği bize biraz fazla kod satırı yazmamıza sebep olacaktı.

Declarative Yaklaşımla Kodlama

Diğer taraftan aynı örneği declarative ui yaklaşımıyla Jetpack Compose kullanarak kodladığımızda çok daha basit ve az satır kodla geliştirme yapabiliriz. Bu örnekte yukarıda bahsettiğim gibi count datasına bağlı olarak dinamik bir şekilde ui çizdiriliyor. Aynı zamanda BadgeEnvolpe composable fonksiyonu her update işleminde tekrardan dataya göre çizilme işlemini gerçekleştirecek.

Sonuç

Bu yazıda Jetpack Compose dünyasına sağlam adımlarla giriş yapmak için derinlemesine bir bakış yapmış olduk. Bir yandan jetpack compose toolkit’ini tanıyarak geliştirme süreçlerini, nelere çözümler sunduğunu öğrendik bir yandan da mantığını ve işleyişini öğrenerek geliştirme öncesi iyi bir şekilde kavradık. Bu yazı, bu serinin ilk yazısı olacak ve diğer kısımlarda Jetpack Compose geliştirmeye başlayacağız ve geliştirirken kullanılan kavramların nelere olduğunu derinlemesine öğrenmeye çalışacağız. Yazının sonunda yararlandığım ve öğrenme aşamasında bana yardımcı olan kaynakları sizlerle paylaşmak istiyorum. Hoşçakalın kodla kalın :)

Dip Not : Bu yazı hakkında eksik veya yanlış gördüğünüz şeyleri paylaşmaktan çekinmeyiniz.

--

--