Tasarım, yazılım projelerinizin vitrinde ön plan çıkmasını sağlayan önemli bir etmendir. Tasarımın göze hitap etmesi haricinde müşterinin projeyi uzun bir süre kullanabilmesi içinde tasarım elementlerine erişilebilirliğin yüksek olması gerekir.
Bu makale de Accessibility Scanner App ile bir Android uygulamasının arayüz elementlerine erişilebilirliğin kolay bir şekilde arttırmasını sağlayarak kullanıcı deneyimini iyileştirmeyi anlatacağım.
Accessibility(Erişilebilirlik) Nedir?
Bir kişinin bir Android cihazı kullanımını etkileyen yaygın durumlar arasında körlük veya az görme, sağırlık veya işitme bozukluğu, kısıtlı motor beceriler, bilişsel engeller ve renk körlüğü yer alır.
Diğer bir yandan bu durumları yaşamayan kullanıcılar da dahi uygulamadaki arayüz elementlerine erişmekte zorluluklar yaşayabildiğinden kaynaklı kullanıcı deneyimini olumsuz etkilenir.
Android uygulamanızdaki erişilebilirlik sorunlarını tespit etmek için Google oluşturduğu Accessibility Scanner uygulamasından yararlanacağız. İlk önce cihazınıza Google Play’den Accessibility Scanner linkinden uygulamayı indirmeliyiz. Adımlar:
Accessibility Scanner uygulamasını kullanabilmek için gerekli izinleri vermeliyiz
Uygulamaya izinleri verdiğimizde yuvarlak mavi icon oluşur. İcon’a tıkladığında inceleme yapmak istediğiniz arayüzün ekran görüntüsünü alırsınız
Accessibility Scanner ekran görüntüsü aldığınız arayüzdeki elementlerin erişilebilirliğini arttırabilmek için önerilerde bulunur.
Bu anlattıklarımı Accessibility Scanner ile nasıl uygulayabileceğimizi gösteren videoyu izleyelim.
Video gösterdiğim üzere Accessibility Example uygulamamızın anasayfasını Accessibility Scanner ile inceledik.
Accessibility Scanner kullanıcı deneyiminin arttırılması gereken öğeleri Şekil-1 deki gibi turuncu çizgilerle belirtir. Şekil-2 de, belirlenen öğelerin id bilgisini verip düzeltilmesi gereken yapıların açıklamalarını listelemektedir.
Elementlerin Erişilebilirliklerini Nasıl Arttıracağız?
Örneğimizde verilen önerileri dikkate alarak çözümler üretelim
Color contrast
Ön plan ve arka plan renkleri arasında yeterli kontrast yoksa, görme bozukluğu olan kullanıcılar ekrandaki bilgileri okumakta daha fazla güçlük çekerler. Düşük kontrast oranları, bazı kullanıcılar için görüntülerin birlikte bulanıklaşmasına neden olabilirken, yüksek kontrast oranları, görüntülerin daha net bir şekilde öne çıkmasını sağlar. Bu yüzden iddeğeri “title” olan arayüz elementimiz için Metin kontrastı uyarısını gösterdi. Bu elementin rengini aşağıdaki videoyayı uygulayarak kontrastını bulalım.
Videoda kontrast oranını uygun renkleri bulduğum için şeklinde doğruladı ve başta 6 tane önerim bulunurken. Şimdi 5 tane kaldı.:) Kontrast yüksek olan rengimizi kodda güncelleyelim.
id değeri imgBack olan ImageButton öğesine kullanıcıların daha rahat tıklayabilmeleri için boyutunu büyütmeyi önermektedir. Odaklanılabilir öğelerin dokunulabilir alanının en az 48dp X 48dp olmasını önermektedir. Sizde bu öneriyi dikkate alarak layout_width ve layout_height değerlerini düzenleyebilirsiniz.
Item Label (Öğe Etiketi)
Accessibility(Erişilebilirlik)’de TalkBack adında bir özellik bulunmaktadır. TalkBack aktif edildiğinde ekrandaki tüm öğeleri sesli bir şekilde okunur. Bu görme yetisi olmayan insanlar için çok önemli bir özelliktir. Bu kullanıcı kitlesini önemsiyorsanız tasarımdaki arayüz elementlerine label(etiket) tanımlamanız gerekir.
TalkBack aktif edebilmek için Settings->Accessibility->Vision tabındaki TalkBack seçeneğini aktif edebilirsiniz. Öğeye etiket eklemek için android:contentDescription özelliğini kullanmalısınız.
Yayınlanan Android uygulamanızın puanlanma ve yorumlarının yapılması indirme sayısına etkisi çok büyüktür. Puanlandırmayı uygulama içinde yaptırılmasıyla müşterinin uygulamada kalmasını sağlayabilirsiniz. Böylelikle kullanıcı deneyimini arttırmış olursunuz.
Bu makalemde, Google Play In-App Review API kullanarak Kotlin dilinde yazılan Android uygulamanın içinde kullanıcının uygulama puanlanma ve yorumlarını yapmasını sağlayan yapıyı örneklendirdim.
Google Play In-App Review API kullanarak Java dilinde yazılan Android uygulamanın makalesine Java ile Google Play In-App Review API linkinden ulaşabilirsiniz.
Örnek projemizin ekran görüntüsü;
In-App Review için Önemli Noktalar
Bu API yalnızca Android 5.0 (API seviyesi 21) veya sonraki sürümlere sahip olan Android cihazlarda çalışır.
Google Play, kullanıcıya ne sıklıkla review dialog arayüzünü gösterilebileceğiniz konusunda zamana bağlı bir kota uygular. Bu kota nedeniyle, launchReviewFlow yöntemini kısa bir süre içinde birden çok kez çağırmak her zaman bir iletişim kutusu görüntülemeyebilir. (örneğin, bir aydan az). Kota hakkında bilgileri quotas linkinden ulaşabilirsiniz.
Google Play bu yapıyı kullanırken tasarımını değiştirmemize olanak sağlamamaktadır.
Kotlin ile geliştireceğimiz projemizde Google Play In-App Review API’yi uygulayabilmek için aşağıdaki belirttiğim adımları uygulamalısınız.
1-Gerekli Kütüphanelerin Eklenmesi
Android Studio Ide ile oluşturduğum projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek Play Core API kütüphanelerini yüklüyoruz.
Kullanıcıdan doğru zamanda puanlandırma istemek için uygulamanızın akışındaki iyi noktaları belirlemeniz (örneğin, kullanıcı bir oyunda bir seviyeyi tamamladığında) çok önemlidir.
İlk önce ReviewManagerFactory sınıfı ile ilgili Activity sınıfında puanlandırma isteğini oluşturmamız gerekir. Sonrasında requestReviewFlow metodundan dönen istediği isSuccessful ile kontrol ettiğimizde sonuç başarılı ise ReviewInfo nesnesi üzerinden launchReviewFlow () yöntemini çağırdık. Bazı nedenlerden dolayı işleyiş başarısız olursa, hatayı log console da göstermesini sağladık.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.google.android.play.core.review.ReviewManagerFactory
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Button'a tıklandığında puanlandırma sistemini çalıştıran metod çağırdım
show_rate_app_btn.setOnClickListener {
inAppReview()
}
}
//Google Play puanlandırma ekranını oluşturan metod
fun inAppReview() {
val reviewManager = ReviewManagerFactory.create(this)
val requestReviewFlow = reviewManager.requestReviewFlow()
requestReviewFlow.addOnCompleteListener { request ->
//Widget açılıp, puanlandırma ve yorum yapılabildiği bölüm
if (request.isSuccessful) {
val reviewInfo = request.result
val flow = reviewManager.launchReviewFlow(this, reviewInfo)
flow.addOnCompleteListener {
//Kullanıcının puanlandırma ekranındaki işlemi bitmiş ve yazılım akışına devam edilecek bölüm
}
} else {
Log.d("Error: ", request.exception.toString())
}
}
}
}
3- Arayüz Kodlama
Activity sınıfımızda kullandığınız arayüz xml sayfasınıza bir button ekledim. Button id değerini de “show_rate_app_btn” yaptım. Üstte kotlin kodlamasında da kullandım.
Yazılımcılar, mobil uygulama içinde kullanıcının sosyal medya ağlarıyla (Facebook, Twitter vb.) bağlantı kurmalarını sağlayarak kullanıcıya kolaylıklar sağlamaktadır.
Bu makalede, Kotlin dili ile Android uygulamasına Facebook API’sini entegre ederek, kullanıcının Facebook hesabına giriş ve profil bilgilerini gösterme işlemlerinin nasıl yapılacağını anlatacağım.
Örneğimizin çıktısı:
Bu uygulamayı oluşturabilmek için sırasıyla adımlarımızı anlatmaya başlayalım.
1-Facebook’da App Oluşturma
developers.facebook.com sayfasını açıp, facebook hesabınıza giriş yaptıktan sonra menüdeki My Apps linkine tıklayın. Açılan sayfada resimde belirttiğim butonu seçmelisiniz.
Sonrasında açılan pencerede “Select an app type” sorusuna cevap olarak Tüketiciseçeneğini seçip, continue butonuna basın. Sonrasında Şekil-1 resminde belirttiğim şekilde App’i oluşturun.
Şekil-1
App oluşturulduktan sonra aşağıdaki resmi göreceksiniz. Facebook Login bölümünde Setupbutonuna basmalısınız.
Ve açılan ekranda Android ikonunuseçmelisiniz. Yeni açılan sayfada yapılması gereken farklı farklı adımlar göreceksiniz. 1. ve 2. adım bölümlerinde hiç birşey yapmadan Nextdiyerek 3. adıma geliniz.
3.adımda Android projenizin paket ismini ve kullanıcı uygulamanızı başlattığında açılacak activity sınıfını belirtiniz ve kaydedin. (Şekil-2)
Şekil-2
Not: Uygulamanızı henüz Google Play mağazasında yayınlamadıysanız, sistemin mağazada uygulamanızı bulamadığını belirten bir açılır pencere görürsünüz. Use this package name butonunu seçip, devam ediniz.
4.adımda uygulamanızın debug ve release versiyonları için hash oluşturacağız.
Uygulamanızı henüz yayınlamadıysanız, yalnızca Debug Key Hash oluşturmalısınız. Daha sonra uygulamayı Google play’e yükleyecekseniz, bu adıma geri dönüp Release Key Hash oluşturmalısınız.
Debug Key Hash Oluşturma
Bu key hash değerini oluşturabilmek için bilgisayarınızda Openssl olması gerekir. Eğer yoksa download linkindeki siteden indirip, exe yi kurabilirsiniz. Bilgisayarınızdaki JDK-> bin dizinin içindeki keytooldosyasını kullanarak hash oluşturacağız. cmddosyasını açıp, aşağıdaki resimde belirttiğim gibi kendi JDK yolunuzu kullanarak bin dizinine gidin.
Sonra openssl ve .android dosya yollarını aşağıdaki komut da yerleştirip, çalıştırın.
Uygulamanızın Apk dosyasını oluştururken ALIAS ve jks uzantılı dosyayı oluştururuz. ALIAS değerini ve jks dosya yolunu aşağıdaki komut da yerleştirip, çalıştırın.
Debug ve Release Key Hash başlıklarındaki bilgiyi uyguladığınızda oluşan key değerini, 4. adımdakiKey Hashes alanına yerleştirip, Save butonuna basın. 5. adım bölümünde hiç bir şey yapmadan Nextdiyerek 6. adıma geliniz.
6. adımdaFacebook App ID ve scheme değerlerinin bulunduğu kodu kopyalayıp, projenizdeki string xml dosyasına ekleyin. Her oluşturulan facebook app de bu değerler farklı olacaktır.AndroidManifest.xml dosyanıza <uses-permission android:name=”android.permission.INTERNET” /> kodunu ekleyerek internet izni verin ve aşağıdaki meta-data ve activity kodunu ekleyin.
Burada yapacağımız işlemler bitti. Diğer adımları Next butonuna basarak geçebilirsiniz.
2-Facebook Login Button Oluşturma
Projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek facebook-login ve Picasso kütüphanelerini yüklüyoruz.
Ben Facebook’un hazır butonuna kullanmayı tercih etmedim. Bunun sebebi tasarımcınızın farklı buton tasarımlarını kullanması durumunda, tasarımı kolaylıkla arayüze aktarmayı göstermektir. MainActivity sınıfında ilişkilendireceğimiz arayüz kodları:
İlk öncelikle Kotlin’de arayüz elementlerinin id bilgilerini kullanarak, elemente kolayca erişmek için id ‘kotlin-android-extensions’ kodunu projemin app dizinin altındaki build.gradle dosyasının plugins alanının içine eklemeliyiz. Bu durumu projede uyguladım.
MainActivity, Facebook hesabına giriş yapıp yapamadığının kontrolünü yaptıktan sonra kullanıcının bazı verilerine ulaşabilmemize sağlayan sınıfdır. Aldığımız bilgileri tasarımda göstermek için DetailsActivity sınıfına aktardım. Daha detaylı açıklama yorum(comment) tag larında bulunmaktadır.
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.facebook.*
import com.facebook.AccessToken
import com.facebook.login.*
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
lateinit var callbackManager: CallbackManager
var id = ""
var firstName = ""
var lastName = ""
var name = ""
var email = ""
var accessToken = ""
//Bu uygulamayı test etmek için strings.xml dosyasına kendi App ID ve Protocol Scheme eklemeyi unutmayın!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
callbackManager = CallbackManager.Factory.create()
facebook_login_btn.setOnClickListener {
LoginManager.getInstance()
.logInWithReadPermissions(this, listOf("public_profile", "email"))
}
//Facebook hesabına giriş yapıp yapamadığının kontrolü
LoginManager.getInstance()
.registerCallback(callbackManager, object : FacebookCallback<LoginResult?> {
override fun onSuccess(loginResult: LoginResult?) {
//Giriş başarılı olduğunda kullanıcı bilgilerini getiren metodu çağırdım
getUserProfile(loginResult?.accessToken, loginResult?.accessToken?.userId)
}
override fun onCancel() {
Toast.makeText(this@MainActivity, "Login Cancelled", Toast.LENGTH_LONG).show()
}
override fun onError(exception: FacebookException) {
Toast.makeText(this@MainActivity, exception.message, Toast.LENGTH_LONG).show()
}
})
}
//Facebook kullanıcısının bilgilerini getiren metod
@SuppressLint("LongLogTag")
fun getUserProfile(token: AccessToken?, userId: String?) {
//Kullanıcının hangi bilgilerini getireceğini belirtiyoruz
val parameters = Bundle()
parameters.putString(
"fields",
"id, first_name, last_name, name, email"
)
GraphRequest(token,
"/$userId/",
parameters,
HttpMethod.GET,
GraphRequest.Callback { response ->
val jsonObject = response.jsonObject
// Facebook Access Token
//Access Token sadece Debug mode'da görebilirsiniz.Kullanıcının access token'nın sızmasını önlemek için yapıldı
if (BuildConfig.DEBUG) {
FacebookSdk.setIsDebugEnabled(true)
FacebookSdk.addLoggingBehavior(LoggingBehavior.INCLUDE_ACCESS_TOKENS)
}
accessToken = token.toString()
// Facebook Name
if (jsonObject.has("name")) {
val facebookName = jsonObject.getString("name")
Log.i("Facebook Name: ", facebookName)
name = facebookName
} else {
Log.i("Facebook Name: ", "Not exists")
name = "Not exists"
}
// Facebook Email
if (jsonObject.has("email")) {
val facebookEmail = jsonObject.getString("email")
Log.i("Facebook Email: ", facebookEmail)
email = facebookEmail
} else {
Log.i("Facebook Email: ", "Not exists")
email = "Not exists"
}
openDetailsActivity()
}).executeAsync()
}
//Login süresinin dolup dolmadığını görmek için AccessToken'ı kontrol ederek
// kullanıcının Login durumunu kontrol eden method
fun isLoggedIn(): Boolean {
val accessToken = AccessToken.getCurrentAccessToken()
val isLoggedIn = accessToken != null && !accessToken.isExpired
return isLoggedIn
}
//Kullanıcının logOut(çıkış) yapmasını sağlayan metod
fun logOutUser() {
LoginManager.getInstance().logOut()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
callbackManager.onActivityResult(requestCode, resultCode, data)
super.onActivityResult(requestCode, resultCode, data)
}
//Kullanıcı bilgilerini DetailsActivity sınıfına aktaran metod
private fun openDetailsActivity() {
val myIntent = Intent(this, DetailsActivity::class.java)
myIntent.putExtra("facebook_name", name)
myIntent.putExtra("facebook_email", email)
startActivity(myIntent)
}
}
Örnek deki detay sayfasının tasarımını yapabilmek için github linkinde bulunan proje içindeki activity_details xml dosyasını kullanabilirsiniz. DetailsActivity sınıfında da activity_details xml’ini kullandık. DetailsActivity sınıfında ise kullanıcı bilgilerini MainActivity sınıfından alıp, arayüz tasarımına aktardık. Profil resmini de Picasso kütüphanesini kullanarak arayüz de gösterilmesini sağladım.
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_details.*
import com.facebook.Profile;
class DetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details)
//facebook name ve email bilgilerini MainActivity'den aldım.
val facebookName = intent.getStringExtra("facebook_name")
val facebookEmail = intent.getStringExtra("facebook_email")
//Bilgileri arayüze aktardım
facebook_name_textview.text = facebookName
facebook_email_textview.text = facebookEmail
//Facebook kullanıcısının profil fotoğrafını alıp,
//Picasso sınıfı ile arayüzde gösterdim
Picasso.get().load(Profile.getCurrentProfile().getProfilePictureUri(400, 400)).into(profil_pic);
}
}
Projenin tüm dosya ve kodlarına githublinkinden ulaşabilirsiniz.
UI, bizim müşteriye göstereceğimiz vitrinimizdir. Bu yüzden yazılımınızın basit, etkili ve kullanıcı dostu bir arayüz tasarımına sahip olması oldukça büyük bir öneme sahiptir.
Bu makale, Android tasarımlarında son zamanlarda trend olan arayüz elementlerinin köşelerini yuvarlatma işlemini en kolay ve iyi nasıl yapabileceğinizi anlatacağım.
Aşağıdaki resimde kullanılan köşeleri yuvarlatılmış öğeleri oluşturmayı örneklendireceğim.
Anlatacağım yöntemler:
CardView ile köşeleri yuvarlatma
Shape xml yapısı ile köşeleri yuvarlatma
1-CardView ile köşeleri yuvarlatma
CardView bir arayüz elementidir. CardView’in cardCornerRadiusadında bir özelliği bulunmaktadır. Bu özelliği ekleyip, sonrasında CardView’in içine koyduğunuz arayüz elementlerinin kapsadığı alanın köşeleri yuvarlatılmış olacaktır.
Peki tüm arayüz elementlerinde bu işlevi eklemek için CardView kullanmak mantıklı mıdır? Eğer tek bir arayüz elementinin köşelerini yuvarlatacaksanız CardView tercih edilmez. Çünkü Shape xml yapısını kullanarak bu işi daha sade ve az kod ile yapabiliriz.:) CardView yöntemi, içeresinde birden fazla arayüz elementlerinin olduğu kapsama alanının köşelerini yuvarlatacağınızda daha çok tercih edilir. (Şekil-1)
Şekil-1
CardView Örneği
İlk örneğimizin görünümü üstteki Şekil-1 deki gibi olacak.:) Bu örneği tamamladıktan sonra tasarıma yeni örnekler ekleyeceğim.
İlk önce bu örnekte kullandığım resimleri https://smality.com/resimler.zip linkinden indiriniz. Sonrasında zip klasörünün içindeki tüm dosyaları alıp, projenizde app->src->main>res yolunu takip ederek, res dizinin içine ekleyin.
Örnek resimde bulunan Vegetables alanını tek başına nasıl yapacağımızı görelim.
EditText, Button, TextView vb. arayüz elementlerinin köşelerini yuvarlatma işlemini daha az kod ile oluşturmak istiyorsanız, shapexml yapısını kullanmalısınız. Örneğin, sayfa tasarımınızda birden fazla köşeleri yuvarlanmış EditText var olduğunu düşünelim. Bu görseli CardView kullanarak kodlarsanız, her bir EditText için ayrı bir CardView oluşturmanız gerekir. Eğer bu tasarımda shapexml yapısını kullanarak kodlarsanız, 1 tane shapexml dosyası oluşturup, bu dosyayı her bir EditText’in background özelliğinde çağırarak 1 satır kodla tüm EditText’lerin köşelerini aynı ölçüde yuvarlarsınız.
Shape xml Örneği
Örneğimizin kodlamasını bitirdiğimizde aşağıdaki gibi bir görüntü elde edeceğiz.
İlk önce projenizde app->src->main>res yolunu takip edip res dizini içindeki drawable dizinine sağ tıklayınız. Açılan pencerede New->Drawable Resource File seçerek drawable xml dosyasını oluşturun ve içine aşağıdaki kod yerleştirin.
Üstteki kodda corners tag’iarayüz elementinin köşelerinde değişiklik sağlar. Corners tag’inin radiusözelliği, belirttiğiniz dpdeğeri kadar köşeleri yuvarlaklaştırır.
Şimdi tek yapmamız gereken işlem, layout xml’deki EditText’in background özelliğine oluşturduğumuz drawable xml’in yolunu eklemektir. (@drawable/rounded_edt)
Yazılım geliştirme süreçlerinde kullandığımız kod derleyici programlar, eğer bilgisayarınızın donanımı güçlü değilse, yazılımcıyı çok fazla uğraştırabilir. Bu durum ciddi enerji ve zaman kaybına sebep olur. Bazı tool’lar bizi bu gibi sıkıntılardan kurtarıp, kod geliştirmeyi kolaylaştırmıştır.
Bu makalede Kotlin kodunuzu JVM, JS, CANVAS ve JUNIT yapılarını kullanarak çalıştırmanıza ve başkalarıyla paylaşmanıza kolaylık sağlayan online bir kod düzenleyicisi Kotlin Playground tool’u anlatacağım.
Kotlin Playground tool nedir? Ne işe yarar?
Kotlin Playground, kod derleyicisi veya IDE gibi programlar kullanmadan bir web sitesi üzerinden Kotlin kodlarınızı oluşturmanıza, çalıştırmanıza ve başkalarıyla paylaşmanıza olanak tanıyan yardımcı bir araçtır.
Kodlar ve test fikirleriyle denemeler yapmanıza izin verir. Bir programlama dilinde yeniyseniz, derleyici veya IDE gibi araçlar yüklemenize gerek kalmadan size hızlı bir şekilde yardımcı olur.
Bu makalede Kotlin Playground kullanarak şunları öğreneceğiz.
Playground, kodlarınızı çalıştırdığında JVM, JS, CANVAS ve JUNIT yapılarıyla destelediğini
Kodlarınızı kolaylıkla başkalarıyla paylaşmayı
Çalıştırılabilir kodu bir web sitesine yerleştirmenize olanak tanır.
Kodu oluşturmak ve çalıştırmak için sağda bulunan RUN ikonuna tıklayın.
Sonuç şu şekilde gözükecektir:
Ayarları Düzenleme
Kotlin Playground aracının farklı farklı özelliklerini kullanmak istiyorsanız, ayarlardaki alanları değiştirmeniz gerekir. Ayarlar bölümüne sağdaki ikonundan ulaşabilirsiniz. Ayarlar ekranındaki alanlar;
Kotlin Version: Programınızı oluşturmak için sürümü seçeceğiniz alan
Program arguments: main fonksiyonunun parametresinden gelecek değeri girdiğimiz alan
Target Platform: Yazdığınız kodun kullanacağı JVM, JS, CANVAS veya JUNIT yapılarından birini seçme bölümüdür.
Playground ‘da JVM yapısının kullanımı
Kotlin, farklı platformlarda çalışabilecek sihirli bir yeteneğe sahiptir. Bu bölümde, Kotlin kodunuz için target platform alanını değiştirmenin ne anlama geldiğini öğreneceksiniz. Ayarlar bölümünü açalım.
JVM target platform’u varsayılan olarak seçilidir. “Hello, world” örneğindeki gibi kodları JVM programını kullanarak çalıştırır.
Playground ‘da JS yapısının kullanımı
JavaScript’i Kotlin dilinde kullanabiliriz. Kotlin / JS, Node.js gibi sunucu tarafında web geliştirmeye ve jQuery ve React gibi istemci tarafında web geliştirmeye olanak tanır. Bu tür projelerde, Kotlin ve JavaScript’in birlikte çalışabilirliği ile ilgili birkaç şeyi denemek isterseniz, Kotlin Playground yardımcı olabilir.
Bu bölümde, JavaScript’i Kotlin’den çalıştırabilmek için target platform’u JS olarak değiştirmelisiniz.
Kodunuzu aşağıdaki gibi düzenleyin.
fun main(args: Array<String>) {
console.log("Hello " + args.joinToString())
js("alert(\"This is an alert\")")
}
Bu kodu çalıştırdığınızda ikinci satırdaki kod; tarayıcınızda alert pencerisi açacaktır ve tarayıcınızda aşağıdaki gibi bir görüntü göreceksiniz.
JS console açınız. Eğer Windows işletim sistemi kullanıyorsanız, F12 tuşuna basarak console sekmesini açabilirsiniz. console.log metodu sonucunda aşağıdaki görüntüyü elde edersiniz.
Playground ‘da CANVAS yapısının kullanımı
HTML5, JavaScript’i kullanarak grafikler çizen Canvas adlı yeni bir öğeyi tanıttı. Basit statik grafikler ve animasyonlar oluşturmanıza ve hatta gerçek zamanlı video oluşturmanıza olanak tanır. Canvas ile etkileşim için Kotlin’i kullanabilirsiniz.
Playground, bir Canvas’ta çizim yapmanıza izin verir. Bu işlemi yapabilmek için ayarlardan target platformu CANVAS seçin ve Program arguments alanını silin.
Kodunuzu aşağıdaki kodla değiştirin.
import org.w3c.dom.CanvasRenderingContext2D
import org.w3c.dom.HTMLCanvasElement
import kotlin.browser.document
import kotlin.browser.window
// HTML Canvas başlatıp, yükseklik ve genilkli değerlerini body e ekledik
val canvas = initalizeCanvas()
fun initalizeCanvas(): HTMLCanvasElement {
val canvas = document.createElement("canvas") as HTMLCanvasElement
val context = canvas.getContext("2d") as CanvasRenderingContext2D
context.canvas.width = window.innerWidth.toInt();
context.canvas.height = window.innerHeight.toInt();
document.body!!.appendChild(canvas)
return canvas
}
val context: CanvasRenderingContext2D
get() {
return canvas.getContext("2d") as CanvasRenderingContext2D
}
fun main() {
//Yazı tipi ve boyutunu belirleyip, HTML Canvas'a Hello Canvas yazdık
context.font = "30px Arial";
context.fillText("Hello Canvas", 10.0, 50.0);
//HTML Canvas'a kırmızı bir dikdörtgen çizdik
context.fillStyle = "#FF0000";
context.fillRect(200.0, 15.0, 50.0, 50.0);
}
Bu kodu çalıştırdığımızda aşağıdaki gibi bir görüntü elde ederiz.
HTML Canvas’ı Kotlin dilinde nasıl kullanabileceğimizi örneklendirdim. HTML Canvas hakkında daha detaylı bilgiyi bu dokümandan elde edebilirsiniz.
Playground ‘da JUNIT yapısının kullanımı
Kotlin Playground tool’da Kotlin testleri yazma, çalıştırma ve hangilerinin başarılı olup olmadığını görme seçeneğiniz de vardır. Bunu yapabilmek için ayarlardan target platformu JUNIT seçmeniz yeterlidir.
En son yazdığınız kodları silip, aşağıdaki kodu yazınız.
data class Family(val name: String, val people: Array<Person>)
data class Person(val lastname: String) {
operator fun plus(person: Person): Family {
return Family(
lastname + " " + person.lastname,
arrayOf(this, this)
)
}
}
Üstteki kodu test edebilmek için, sayfanın en üst bölümüne aşağıdaki kodu ekleyin.
import org.junit.Assert
import org.junit.Test
class PersonTest {
// 1
@Test
fun `Person + Person should create Family containing each Person`() {
val personOne = Person("Cortazzo")
val personTwo = Person("Sproviero")
val family = personOne + personTwo
Assert.assertEquals(arrayOf(personOne, personTwo), family.people)
}
// 2
@Test
fun `Person + Person should create Family concatenating lastnames`() {
val personOne = Person("Cortazzo")
val personTwo = Person("Sproviero")
val family = personOne + personTwo
Assert.assertEquals("Cortazzo Sproviero", family.name)
}
}
Test kodumuz ne gibi işler yapıyor:
1. yorum tag bölümündeki test: Family sınıfının her bir Person nesnesini içerip içermediğini kontrol eder.
2. yorum tag bölümündeki test: Person sınıfının lastname değerlerini birleştirip, Family’deki name parametresiyle aynı olup olmadığını kontrol eder.
Kodun çıktısı:
plus fonksiyonunu incelerseniz, problemin diğer person’u eklemek yerine kendisini diziye iki kez eklemesi olduğunu göreceksiniz. İşlevi aşağıdaki kodla değiştirerek düzeltebilirsiniz.
operator fun plus(person: Person): Family {
return Family(
lastname + " " + person.lastname,
arrayOf(this, person)
)
}
Playground ‘daki Kodların Paylaşımı
Kotlin Playground’ da yazmaya devam ettiğiniz kodları, herhangi bir program kullanmadan diğer insanlarla paylaşıp, kod takibi yapmalarını sağlayabilirsiniz. Bu işlemi yapabilmek için sağdaki ikonuna tıklamalısınız. Sonrasında aşağıdaki ekran açılacaktır.
Bu resimde kırmızı ile belirtiğim ikonu tıklayıp, kodun bulunduğu linki kopyalayıp, paylaşmak istediğiniz kişiye gönderebilirsiniz.
JS Script ile Playground ‘daki Kodları Siteye Ekleme
Web sitenizde Playground’ da yazdığınız Kotlin kodunu çalıştırılabilir halini gösterme imkanınız bulunmaktadır. HTML’ye bir JS komut dosyası ekleyerek bu işlemi yapabilirsiniz. Dilerseniz web site testinizi https://codepen.io/pen/ gibi çalışma alanında yapabilirsiniz. Bir örnek yapalım.
HTML alanına aşağıda anlattığım gibi kodları ekleyelim.
Yazılım projelerinde, kullanıcıların istek ve beklentilerini öngörerek bunları kullanıcı arayüz ekranlarına doğru ve işlevsel bir tasarım olarak aktarmak çok önemlidir. Bu yüzden, tasarımda kullanıcı deneyimini arttıran elementler kullanmanın önemi büyüktür.
ViewPager yapısından ViewPager2’ye geçişin avantajları ve bir Android uygulamasında ViewPager2 kullanımı konularıyla ilgili “Android ViewPager2 Kullanımı” makalemden bilgi edinebilirsiniz.
Carousel efekti ile resimleri slide olarak görüntüleyen örneğin ekran görüntüsü;
ViewPager2 widget, android.support kütüphanesinde bulunmamaktadır. ViewPager2 kullanabilmek için AndroidX kütüphanesine geçmeniz gerekir.
Dilerseniz AndroidX Kütüphanesine Geciş adlı makalemi okuyarak, var olan projelerinizi AndroidX yapısına kolaylıkla geçişini sağlayabilirsiniz.
Android Studio Ide ile oluşturduğum projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek Viewpager2 kütüphanesini yüklüyoruz.
Örneğimizi oluşturabilmek için 2 tane Java sınıfı kullandım. İlk önce MainActivity sınıfında, ViewPager2 widget’ının hangi yönde slide işlemini yapacağını tanımladık. Sonrasında MyAdapter sınıfındaki resim nesnelerini ViewPager2’ye yükleyebilmek için setAdapter metodunu kullandık.
ViewPager2 nesnesinin setPageTransformer metodundan faydalanarak, ViewPager2 widget’da bulunacak resimlere carousel efekti eklendi. Daha detaylı açıklama kodlar arasındaki açıklamalarda bulunmaktadır.
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
ViewPager2 myViewPager2;
MyAdapter MyAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_java);
myViewPager2 = findViewById(R.id.viewpager);
MyAdapter = new MyAdapter(this);
//ViewPager2 widget'ın yatay pozisyonda gösterilmesini sağlıyoruz
myViewPager2.setOrientation(ViewPager2.ORIENTATION_HORIZONTAL);
//MyAdapter sınıfındaki resim nesnelerini ViewPager2'ye yükleniyor
myViewPager2.setAdapter(MyAdapter);
myViewPager2.setOffscreenPageLimit(3);
float pageMargin= getResources().getDimensionPixelOffset(R.dimen.pageMargin);
float pageOffset = getResources().getDimensionPixelOffset(R.dimen.offset);
//ViewPager2 widget'da bulunan resimlerin carousel efekti ile gösterimi
myViewPager2.setPageTransformer(new ViewPager2.PageTransformer() {
@Override
public void transformPage(@NonNull View page, float position) {
//Belirli margin değerleri ile ViewPager2 widget'ın sayfadaki
//konumu hesaplanıp X ve Y ordinatlarında kullanarak efekt sağlanıyor.
float myOffset = position * -(2 * pageOffset + pageMargin);
if (myViewPager2.getOrientation() == ViewPager2.ORIENTATION_HORIZONTAL) {
if (ViewCompat.getLayoutDirection(myViewPager2) == ViewCompat.LAYOUT_DIRECTION_RTL) {
page.setTranslationX(-myOffset);
} else {
page.setTranslationX(myOffset);
}
} else {
page.setTranslationY(myOffset);
}
}
});
}
}
MyAdapter.java, ViewPager2 widget’ının içinde gösterilecek, resimlerimizi eklediğimiz sınıftır. ImageView nesnenini tanımlayıp, drawable dosyasındaki resimlerimizi atadık. Daha detaylı açıklama kodlar arasındaki açıklamalarda bulunmaktadır.
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
private Context context;
public MyAdapter(Context context) {
this.context = context;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//Kullanılacak arayüz xml dosyasını çağırıyoruz
View view = LayoutInflater.from(context).inflate(R.layout.row_item, parent, false);
return new MyViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
//ViewPager2 widget'da gösterilecek resimlerimizi ImageView nesneni yüklüyorüz.
int images[]={R.drawable.nature1,R.drawable.nature2,R.drawable.nature3,R.drawable.nature4};
holder.imgBanner.setImageResource(images[position]);
}
@Override
public int getItemCount() {
return 4;
}
//ViewPager2 widget içinde kullanacağımız ImageView nesneni tanımlıyoruz
public class MyViewHolder extends RecyclerView.ViewHolder {
ImageView imgBanner;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imgBanner = itemView.findViewById(R.id.imgBanner);
}
}
}
3-Arayüz Kodlaması
Örneğimizdeki görüntüyü elde etmek içim, 2 tane xml dosyasında kodlama yapmamız gerekmektedir.
activity_main xml kodlarımızda ViewPager2 nesnesini ekledik. MainActivity sınıfında kullandık.
Yazdığınız uygulamanın kullanıcı sayısının artmasını sağlayan en önemli konulardan biri, kullanıcı deneyimi yüksek ve dikkat çekici tasarıma sahip olmasıdır.
Android uygulama da UI öğeleri arasındaki geçişleri farklı animasyon görünümleri ile sağlayan çeşitli Material motion özellikleri bulunmaktadır. Bu özelliklerden biri olan Shared Axis hakkındaki örnek projeyi “Material Motion Part 1: Shared Axis” adlı makalemden ulaşabilirsiniz.
Bu makale serisinde, Android uygulamada iki farklı arayüz elementinin birbirleri arasında animasyonlu bir şekilde geçişini sağlayan Material motion Container Transform özelliğini örnekleyeceğim.
Container Transform
Bir arayüz elementinin başka bir arayüz elementine animasyonlu bir şekilde geçişini sağlayan özelliktir. Böylelikle kullanıcının mobil tasarım öğeleriyle etkileşime girmesini sağlamış oluruz. Bu durum projenin uzun vadede kullana bilirliğini artırır.
Makalemizde anlatacağım örnek uygulamanın görüntüsü;
Bu örneği uygulayabilmek için işlemleri adım adım yapalım.
1-Gerekli Kütüphanelerin Yüklenmesi
Projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek navigation ve material kütüphanelerini yüklüyoruz.
İlk önce Note sınıfından bahsetmek istiyorum. Tüm not başlıklarını, içeriklerini ve not kutularının renklerini atadığım ve bu değerleri bir listOf array yapısında barındırdığım sınıfdır.
import androidx.annotation.ColorRes
data class Note(
val id: Int,
val title: String,
val body: String,
@ColorRes val colorRes: Int
)
val note1 = Note(
id = 1,
title = "ToDo 1",
body = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus scelerisque placerat nisl, nec semper felis ullamcorper vel. Nullam egestas ante nec tortor egestas mattis. Duis ut diam nec nibh sodales commodo at at diam. Nunc tempor eu lectus ut feugiat. Etiam eget ullamcorper est, at scelerisque lectus. Aliquam erat volutpat. Maecenas est urna, vestibulum non eros non, dignissim feugiat mi. Cras sit amet ex hendrerit, accumsan dolor in, bibendum erat. Maecenas ullamcorper ut risus eget congue. Vestibulum aliquam ipsum ut turpis efficitur, vel malesuada neque aliquam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean egestas justo id rutrum blandit. Vestibulum id orci libero. Aliquam pharetra sed mauris ac vehicula.",
colorRes = R.color.blue300
)
val note2 = Note(
id = 2,
title = "ToDo 2",
body = "Fusce hendrerit enim in eros congue, sed pharetra libero tempus. Integer accumsan euismod nibh non vestibulum. Curabitur finibus imperdiet nunc vel ornare. Ut maximus fringilla sapien in viverra. Aenean a nulla feugiat, hendrerit risus et, congue erat. Ut venenatis lorem sit amet volutpat sollicitudin. Donec ac lorem auctor sem mattis faucibus non ac ante. Phasellus id sem non ante bibendum porta non in tellus. Etiam pellentesque porta luctus.",
colorRes = R.color.amber300
)
val note3 = Note(
id = 3,
title = "ToDo 3",
body = "Praesent interdum dictum magna quis pretium. Suspendisse at cursus ante, id rutrum nunc. Nullam at lacinia nibh, nec gravida lectus. Quisque maximus vulputate leo, et sollicitudin turpis luctus pellentesque. Nullam vehicula sagittis magna, consectetur congue neque ullamcorper vel. Praesent sed vulputate nunc. Ut ligula lorem, lobortis tristique interdum at, mollis a dolor. Ut sed fringilla urna, id suscipit justo. Praesent ut tortor pharetra, laoreet metus non, iaculis mi. Duis vel lacus fermentum, porta neque id, ultricies arcu. Nunc interdum, est ac sodales tristique, elit urna feugiat dui, quis venenatis ante lorem ullamcorper mi. Nulla id condimentum lorem. Nunc ac scelerisque felis. Nam semper, mi et ultrices rutrum, neque odio molestie tortor, ac iaculis ante arcu eu elit. Phasellus imperdiet tortor quis aliquam ornare.",
colorRes = R.color.green300
)
val notes = listOf(note1, note2, note3)
MainActivity sınıfımızda ise, notların grid şeklinde gösterilmesi sağlayan ve not kutucuklarına tıklandığı anda yapılan geçiş animasyonunu tetiklemesini yaptık. Detaylı açıklamalar kodlar arasında bulunmaktadır.
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.MenuItem
import androidx.core.app.ActivityOptionsCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.card.MaterialCardView
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setRecyclerView()
}
private fun setRecyclerView() {
//Note data class da tanımlanan başlık ve içerikler NotesAdapter sınıfına gönderiliyor
val adapter = NotesAdapter(notes)
//Not kutularına tıklanma eventi
adapter.noteClickListener = object : NotesAdapter.NoteClickListener {
override fun onNoteClick(id: Int, noteCard: MaterialCardView) {
val intent = Intent(this@MainActivity, NoteDetailActivity::class.java)
//Not kutusuna tıkladığı anda yapılan geçiş animasyonunu tetiklediğimiz bölüm
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
this@MainActivity, noteCard, id.toString()
)
//İlgili içeriğin id'si NoteDetailActivity sınıfına gönderiliyor
intent.putExtra("noteId", id)
startActivity(intent, options.toBundle())
}
}
//Notları grid şeklinde gösterilmesi sağlayan bölüm
recycler_view.layoutManager = GridLayoutManager(this, 2)
recycler_view.adapter = adapter
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
onBackPressed()
true
}
else -> {
true
}
}
}
override fun onBackPressed() {
finish()
}
}
Notların grid şeklinde gösterilmesi için activity_main xml dosyasında RecyclerView arayüz elementi kullanıldı.
NotesAdaptersınıfının işlevi, MainActivity sınıfında kullanılan RecyclerView içinde tüm not item’larını oluşturmaktır. Bu item kutucuklarında da Note sınıfından gelen notlarla ilgili içerikleri item_note xml dosyasına aktarmasıyla tasarımda gösterilmesidir.
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.smality.materialcontainertransform.databinding.ItemNoteBinding
import com.google.android.material.card.MaterialCardView
class NotesAdapter(private val items: List<Note>) : RecyclerView.Adapter<NotesAdapter.ViewHolder>() {
lateinit var noteClickListener: NoteClickListener
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
ViewHolder(
ItemNoteBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) = holder.bind(items[position])
inner class ViewHolder(val binding: ItemNoteBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(note: Note) {
binding.note = note
binding.noteCard.transitionName = note.id.toString()
binding.noteCard.setOnClickListener {
noteClickListener.onNoteClick(note.id, binding.noteCard)
}
}
}
interface NoteClickListener {
fun onNoteClick(id: Int, noteCard: MaterialCardView)
}
}
item_note xml dosyasında MaterialCardView arayüz elementini notları kutucuk şeklinde göstermek için kullandık. MaterialCardView içinde de MaterialTextView arayüz elementine not başlık ve içeriklerini atadık.
Son olarak, NoteDetailActivity sınıfını kullandık. Bu sınıf, not kutularına tıklandığında notların detaylandırının gösterildiği sayfadır. Diğer bir yandan bu sınıfta, RecyclerView nesnesinden MaterialTextView nesnesine geciş anının süresinin belirlendiği kod sayfasıdır. Detaylı açıklamalar kodlar arasında bulunmaktadır.
import android.os.Bundle
import android.view.MenuItem
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.google.android.material.transition.platform.MaterialContainerTransform
import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback
import com.smality.materialcontainertransform.databinding.NoteDetailActivityBinding
class NoteDetailActivity : AppCompatActivity() {
private lateinit var binding: NoteDetailActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
binding = NoteDetailActivityBinding.inflate(layoutInflater)
//MainActivity sınıfından gelen noteId değerini aldık
val noteId = intent.getIntExtra("noteId", 0)
//Id bilgisine göre Note data class daki not içeriğini alıp, note nesnesine atadık
val note = notes.find { it.id == noteId }
binding.note = note
//
binding.coordinator.transitionName = noteId.toString()
setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
//buildContainerTransform metodunda oluturulan özelliklerin geciş esnasında uygulanması için
//yapılan atama
window.sharedElementEnterTransition = buildContainerTransform()
window.sharedElementReturnTransition = buildContainerTransform()
setContentView(binding.root)
super.onCreate(savedInstanceState)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
}
//RecyclerView nesnesinden MaterialTextView nesnesine geciş anının süresini belirkeyen metod
private fun buildContainerTransform() =
MaterialContainerTransform().apply {
addTarget(binding.coordinator)
duration = 300
//geçiş anındaki animasyon hızını ayarlayan metod
interpolator = FastOutSlowInInterpolator()
fadeMode = MaterialContainerTransform.FADE_MODE_IN
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
onBackPressed()
true
}
else -> {
true
}
}
}
}
note_detail_activity xml dosyasında ise, MaterialTextView arayüz elementi kullanılarak seçilen notun detaylarının gösterildi.
Yazılım projeleri oluştururken hazırladığımız veritabanı yapılarını, bir arayüz alanı üzerinden incelemek, değişiklik yapmak her zaman işimizi kolaylaştırır. Android uygulama geliştirme sürecinde yakın zamana kadar local veritabanı üzerinde değişiklikler yapmak, biz geliştiriciler için hayli zordu.
Bu makalemde Android Studio 4.1 ile gelen Database Inspector özelliği sayesinde projelerinizde SQLite veya Room ile oluşan veritabanlarında nasıl kolay bir şekilde sorgular çalıştıracağınızı ve incelemeler yapacağınızı göstereceğim.
İlk öncelikle Android Studio sürümünüzü 4.1 şeklinde güncellemeniz gerekmektedir.
Android Studio menüsünde View > Tool Windows > Database Inspector yolunu izleyerek, Database Inspector özelliğini açabilirsiniz.
Database Inspector özelliğini kullanabilmek için test ortamınızın API level 26 veya 26’dan büyük olmalıdır.
Özelliği aktif ettiğim örnek görünüm;
Test cihazınızda daha önceki projelerinizde oluşturduğunuz veritabanları olabilir. Sizin projenize ait veritabanına ulaşmak için Şekil-1 belirttiğim ilgili yerden, projenizin paketini seçmelisiniz.
Şekil-1
Database Inspector Sorgu Çalıştırma
Room kütüphanesi ile veritabanı oluşturduysanız, @Query etiketi içinde olan sorguları hızlıca çalıştırma ve sonucunun gösterilmesi sağlanmaktadır. Klasik SQLite yapısında da benzeri yapı bulunmaktadır. Fakat bu kullanımda, koddaki sorguları çalıştırmak her zaman mümkün olmayabiliyor.
İki farklı şekilde sql sorgularınızı çalıştırabilirsiniz
1- @Query etiketin sol tarafındaki arama simgesine tıkladığınızda, kodda bulunan sorgu çalışır. Örneğin, id değeri “4463f016-350d-441f-b2a4-26c6b1dba973” olan notu listeleyelim.
2- Database Inspector arayüzünde sorgu yazma alanını açarak da sql çalıştırabilirsiniz. Örneğin, bir tane ders notunu veritabanına ekleyip, sonrasında bu kaydı select sql listeleyelim.
Veritabanında Kolay Veri Değişikliği Nasıl Sağlanır
Database Inspector kullanarak, çalışan uygulamanın veritabanındaki verileri anlık hızlı bir şekilde değiştirme imkanımız bulunmaktadır.
Diğer özellik ise uygulamada verilerle ilgili yapılan değişiklikleri, anında canlı bir şekilde veritabanında görme imkanımız bulunmaktadır. Bu özelliği kullanabilmek için ilgili tablomuzu açtıktan sonra Live updates checbox seçmeliyiz. Aşağıdaki örnek resimde, “service” notunu eklediğimde otomatik olarak tabloda kayıt olduğunu göreceksiniz.
Android uygulamanız Play Store’da yayınlandıktan sonra, uygulama puanlandırma ve yorumları daha fazla indirme sağlamak için çok önemli faktörlerdir. Bunu başarmak için, genellikle kullanıcıları Play Store’a yönlendirerek uygulamayı puanlandırmalarını isteriz. Bu yöntem ile kullanıcıların Play Store’a yönlendirildikten sonra uygulamanıza geri dönmeme olasılığı vardır. Ayrıca bazı kullanıcılar, uygulamayı Play Store’da puanlandırmak da zorlanabilir.
Bu makalemde, Google Play In-App Review API ile kullanıcının uygulama puanlandırma ve yorumlarını, Android uygulama içinde yapmasını sağlayarak, indirme sayılarını arttırma konusunda fayda sağlayacağız.
Aşağıdaki resimde olduğu gibi kullanıcı, uygulama içinde puanlandırma ve yorum yapabilir.
In-App Review için Önemli Noktalar
Bu API yalnızca Android 5.0 (API seviyesi 21) veya sonraki sürümlere sahip olan Android cihazlarda çalışır.
Google Play, kullanıcıya ne sıklıkla review dialog arayüzünü gösterilebileceğiniz konusunda zamana bağlı bir kota uygular. Bu kota nedeniyle, launchReviewFlow yöntemini kısa bir süre içinde birden çok kez çağırmak her zaman bir iletişim kutusu görüntülemeyebilir. (örneğin, bir aydan az). Kota hakkında bilgileri quotas linkinden ulaşabilirsiniz.
Rating widget üzerinde tasarımsal bir değişiklik yapamazsınız. Bu konuda daha detaylı bilgiyi Design Guidelines linkinden ulaşabilirsiniz.
Projemizde Google Play In-App Review API’yi uygulayabilmek için aşağıdaki belirttiğim adımları uygulamalısınız.
1-Gerekli Kütüphanelerin Eklenmesi
Android Studio Ide ile oluşturduğum projemin app dizinin altındaki build.gradle dosyasını açıyoruz. Dependencies kod bloklarının arasına aşağıdaki kodları yerleştirerek Play Core API ve material kütüphanelerini yüklüyoruz.
implementation "com.google.android.play:core:1.8.0"
//material'i hata geri dönüşü olduğunda kullanıcı deneyimi için kullanıldı
//isterseniz, alternatif kütüphanelerde kullanabilirsiniz
implementation "com.google.android.material:material:1.3.0-alpha02"
2- Backend Kodlama
İlk önce ReviewManager interface oluşturmamız gerekir. Sonrasında review akışını başlatmak için ReviewInfo nesnesi üzerinden launchReviewFlow () yöntemini çağırdık. Bazı nedenlerden dolayı işleyiş başarısız olursa, kullanıcıyı playstore uygulamasına yönlendirip, klasik playstore üzerinden değerlendirme yapılmasını sağladım. Detaylı açıklamalar kodlar arasında comment olarak bulabilirsiniz.
import android.content.*;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.play.core.review.*;
import com.google.android.play.core.tasks.Task;
public class MainActivity extends AppCompatActivity {
private ReviewManager reviewManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
reviewManager = ReviewManagerFactory.create(this);
findViewById(R.id.btn_rate_app).setOnClickListener(view -> showRateApp());
}
/**
* In-App review API'nin sağladığı rating widget ve alt sayfalarını gosteren metod
*Rating widget kotalara ve sınırlamalara bağlı olarak gösterilebilir veya gösterilmeyebilir
*/
public void showRateApp() {
Task<ReviewInfo> request = reviewManager.requestReviewFlow();
request.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
ReviewInfo reviewInfo = task.getResult();
Task<Void> flow = reviewManager.launchReviewFlow(this, reviewInfo);
flow.addOnCompleteListener(task1 -> {
//Rating widget gösterilme işlemi bitti. Yalnız bu noktada API'de, kullanıcının puanlandırma yapıp yapmadığıyla
//ilgili bir kontrol bulunmamaktadır
});
} else {
//Herhangi bir hata varsa showRateAppFallbackDialog metodu çağırılıyor
showRateAppFallbackDialog();
}
});
}
/**
* bir hata ile karşılaşıp, uygulama içinde Rating widget gösterilemediği durumda,
* uygulamanızı PlayStore yönlendirip, PlayStore web sitesinde puanlandırma yapılmasına yönlendirdim.
*/
private void showRateAppFallbackDialog() {
//Ben tercih olarak MaterialAlertDialogBuilder kullandım. Fakat dilerseniz, klasil AlertDialog da kullanabilirsiniz
new MaterialAlertDialogBuilder(this)
.setTitle(R.string.rate_app_title)
.setMessage(R.string.rate_app_message)
.setPositiveButton(R.string.rate_btn_pos, (dialog, which) -> redirectToPlayStore())
.setNegativeButton(R.string.rate_btn_neg,
(dialog, which) -> {
})
.setNeutralButton(R.string.rate_btn_nut,
(dialog, which) -> {
})
.setOnDismissListener(dialog -> {
})
.show();
}
//Kullanıcıyı PlayStore yönlendirme(Hata ile karşılaşıldığında kullandım)
public void redirectToPlayStore() {
final String appPackageName = getPackageName();
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
} catch (ActivityNotFoundException exception) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
}
}
}
3- Arayüz Kodlama
Ben MaterialButton kullanarak, kullanıcıdan değerlendirme yapmasını yönlendirdim. Siz dilerseniz, klasik button da kullanabilirsiniz. In-App Review API’den bağımsız, sizin tasarım tercihinizle alakalı bir durum.
Eğer benim gibi MaterialButton kullanacaksanız, res->values ->styles.xml dosyasınızda temanız MaterialComponents şeklinde tanımlanmış olmalıdır. Örnek;
In-App Review API’sini barındıran proje kodlarını test edebilmek için uygulamanızı PlayStore’da onaylatmış olmanız gerekir. En azından uygulamanızı PlayStore’da Internal Testing ve Internal App Sharing test ortamlarına yüklemelisiniz.
Örnek proje kodlarına github linkinden ulaşabilirsiniz.
Yazılım projelerini oluşturma aşamasında harcanan zaman herkes için çok değerlidir. Proje için harcanan zamanı en aza indirmek, maddi ve manevi birçok getirileri bulunmaktadır. Android uygulama geliştirme süreçlerinde birden fazla yöntem ile zaman kazancı sağlayabilirsiniz. Android Studio’da Build Analyzer Kullanımı ve Debug Püf Noktaları adlı makalelerimde farklı 2 yöntemden bahsetmiş bulunmaktayım.
Bu makalemde ise Android Studio Gradle 6.6 sürümünün, yapılandırma sürecinin sonucunu önbelleğe alarak, bu bilgiyi bir sonraki derlemelerde kullanmasıyla performansı önemli ölçüde artıran “Configuration Caching” özelliği anlatacağım.
“Configuration Caching” özelliğinde ek olarak, yapılandırma önbelleğini yeniden kullanırken, varsayılan olarak daha fazla iş paralel olarak çalıştırılır. Yapılandırma ve yürütme aşamalarının izolasyonu ve görevlerin izolasyonu, bu optimizasyonları mümkün kılar.
Not: Yapılandırma önbelleğini kullanan Gradle, yapılandırma komut dosyaları gibi derleme yapılandırmasını etkileyen hiçbir şey değişmediğinde yapılandırma aşamasını tamamen atlayabilir.
Configuration Caching Özelliğini Aktif Etme
Configuration caching özelliği, Gradle 6.6 sürümünde bulunmaktadır. Bu özelliği aktif edebilme için gradle dosyasında bir komut çalıştıracağız. Android Studio’da komut çalıştırmak için View->Tool Windows->Terminal sekmesini açmalısınız. Terminal adlı pencere, Android Studio aşağı kısmında açılacaktır. Burada proje yolununda yazmış olduğu komut yazma alanını göreceksiniz. Windows ve Linux(veya Mac) işletim sistemlerinde yazılan gradle komutları biraz farklıdır. Örneğin, gradle versiyonunuzu öğrenmek isterseniz,
Windows ‘da “gradlew –v”, Linux(veya Mac) işletim sistemlerinde ise “./gradlew –v” yazmalısınız.
Configuration caching özelliğini aktif etmek ve yardımı çalıştırmak için;
Windows işletim sisteminde
gradlew --configuration-cache help
Linux veya Mac işletim sisteminde
./gradlew --configuration-cache help
şeklinde komutları kullanmalıyız.
Örnek;
Configuration caching özelliğini aktif etmenin diğer bir yolu, proje ana dizinindeki gradle.properties dosyasını açıp,
org.gradle.unsafe.configuration-cache=true
kodunu ekleyerek yapabilirsiniz. Bu yöntemle özelliği aktif ederseniz, her derlemede komut satırı tarafına geçmeden Configuration caching kullanmış olursunuz.
Java Build
Yaklaşık 500 tane alt projeye ve karmaşık yapı mantığına sahip büyük bir Java enterprise projesi, normalde 8 saniyede çalışırken, Configuration caching özelliği kullandığımızda ise 0,5 saniyede derlendiğini gördük.Böylelikle Configuration caching özelliği ile 16 kat daha hızlı derlemiş oldu. Aynı yapıda, uygulama kodunu değiştirdikten sonra assemble çalıştırmak, 40 saniyede derlenirken, 13 saniye gibi bir sürede, yani yaklaşık 3 kat daha hızlı derlenmesine sebep oldu. Bu örneğin grafiği aşağıdadır.
gradle/gradle projesinin derleme anını inceleyelim . Bu proje yüz tane alt proje ve karmaşık bir yapıya sahiptir.
Uygulamada değişikliği yaptıktan sonra test yaptığımızda aşağıdaki grafikte, mavi alanda configuration phase(yapılandırma aşaması), yeşil alanda ise execution phase bilgisini görebilirsiniz. Grafiğin sol tarafında , configuration caching(yapılandırma önbelleği) etkinleştirilmeden, yapılandırma aşaması 2 saniyeden fazla sürerken, grafiğin sağ tarafında configuration caching ile 214 milisaniyeye inmektedir.Yani 2 saniyeden 214 milisaniyeye düşerek, zamandan kazanmış olduk.
Android builds
2500 alt projeye sahip çok büyük bir Android uygulamasının derleme zamanlarını inceleyeceğiz. Bu projeyi normal derlediğimizde 25 saniyede, configuration caching ile derlediğimizde ise 0,5 saniyede çalışmaktadır. Yani configuration caching sayesinde 50 kat daha hızlı derlendi. Bazı alt uygulamaları değiştirdikten sonra APK’yi bir araya getirmek gibi daha kullanışlı bir derleme çalıştırmak, ~ 50 saniyeden ~ 20 saniyeye, neredeyse 3 kat daha hızlı yapılabiliyor.
Kendi Android uygulamalarınızda, yukarıda gibi zaman ölçümleri yapmak istiyorsanız, bu github reposunda talimatları izleyerek, Gradle Profiler den yardım alarak yapabilirsiniz.