Kotlin Temelleri
Veri tiplerini değiştirme
//İnt dan String
int myNumber = 5
myNumber.toString()
.toInt()
.toLong()
//Gibi kullanımları bulunmakta
Null değer verme
var myAge: Int? = null
println(myAge)
//Artık int bir null
//peki ben null bir değer ile 10 sayısını çarpabilirmiyim
println(myAge!! * 10)
/*Artık dedikki myAge kesin bir değer alıcak şuan null ama bir yerden
değer çekicek dedik*/
Güvenli Kodlar
Güvenli kodlar programımızın çökmesini engeller ve kullanıcıya bir bildiride bulunur buyüzden çok önemlidir
// 1.metot Null Safety
var myAge: Int? = null
println(myAge)
if(myAge != null){ //Eğer myAge doluysa
println(myAge * 10) //10 ile çarp
}
else{ //Değil ise myAge null yazdır
println("myAge null")
}
//2.metot elvis
val myResult = myAge.compareTo(2) //myResult u myAge eşitler fakat
// myAge null ise hata verir bunu şöyle engelleyebilirsin
println(myResult)
val myResult = myAge.compareTo(2) ?: -100 //Eğer myAge null ise değeri
// -100 ile eşitler
Collections
Array
val myArray = arrayOf("James","Kirk","Rob") //Tanımladığımız elemanın türünü belirler
println(myArray[0])//James bize getirir 1.Yol
println(myArray.get(0)) //2.Yol
val intArray = intArrayOf(0) //Maksimum 10 adet eleman alabilir
println(intArray[0])//0 bize çağır 1.Yol
println(intArray.get(0))// 2. Yol
val stringArray = arrayOf("")//Maksimum 10 adet eleman gelebilir
println(stringArray[0])// bize getirir 1.Yol
println(stringArray.get(0))//2.Yol
val doubleArray = doubleArrayOf(1.0)//Makismum 10 eleman gelebilir
println(doubleArray[0])//1.0 ı bize getirir 1.Yol
println(doubleArray.get(0))// 2.Yol
//Eğer elemanları değiştirmek istersek
myArray[0] = "James Hartfield"
myArray.set(0) = "Escan"
//Array eleman ekleme
var myArray = arrayof(0)//int değer oluşturabiiyoruz ilk eleman 0
myArray.set(1,8)//ikinci değeri atadık
myArray.set(2,34)// 3. değeri atadık
myArray.set(3,19)// 4. değeri atadık
myArray.set(4,26)// 5. değeri atadık
myArray.set(5,31)// 6. değeri atadık
myArray.set(6,-5)// 7. değeri atadık
myArray.set(7,78)// 8. değeri atadık
Listeler
val myMusician = ArrayList<string>() //String bir liste oluşturduk
myMusician.add("Escan") //Listemize Escan elemanını ekler
println(myMusician[0])
val myMixedArrayList = ArrayList<Any>() //Herhangi bir türden veri atabilirsiniz
myMixedArrayList.add("Escan")
myMixedArrayList.add(250)
myMixedArrayList.add(true)
println(myMixedArrayList[0])
println(myMixedArrayList[1])
println(myMixedArrayList[2])
Setleme
Setler içerisinde 1 eleman birden fazla kez kullanılamaz
val mySet = setOf<int>(2,3,4,1)
mySet.foEach{println(it)} // Tek tek değerleri it değişkenine atar ve yazdırır
HashSet
HashSet de parantez içine eleman yazdırılmak yerine add komutuyla eklenir. Aynı elemanlardan 1 defa ekler
val hSet = HashSet<String>()
hSet.add("Yunus")
hSet.add("Yunus")
hSet.add("Yunus")
hSet.add("Yavuz")
hSet.forEach() {
println(it)
}
println(hSet)
// out put: Yunus
//Yavuz
//Tek bir set çekmek istersek
var put = hSet.elementAt(2) // bu şekilde 3. indexi seçeriz
println("3. index in değeri ${put}")//bu şekilde de yazdırırız
HashMap
Bize dizileri yada verileri birbiriyle eşleştirme imkanı sunuyor bunun anlamı ise Key - Value dur
val fruitCaloriMap = hashMapOf<String,int>()
fruitCaloriMap.put("Apple",150) //Elma elemanı eklenir ve buna 150 sayısı value olarak tanır
println(fruitCaloriMap["Apple"]) //Elmayı yazdırır
When
Eğer çok fazla else ifiniz var ise kullanılır
var day = 3
var dayString = ""
if(day == 1){
dayString = "Monday"
}
else if(day == 2){
dayString="Tuesday"
}
else if(day == 3){
dayString="Wednessday"
}
println(dayString)
//When ile kullanımı
var day = 3
var dayString = ""
when(day){ //değer ... olduğu zaman
1-> dayString = "Monday" //day 1 olduğu zaman
2-> dayString = "Tuesday"
3-> dayString = "Wednessday"
else -> daystring ="" //Değer yok ise
}
println(dayString)
Döngüler
For
For Kotlinde c# daki Foreach görevini görüyor
var myArrayOfNumbers = arrayOf("12","23","32","65")
for(number in myArrayOfNumbers){
val z = number / 3*5
println(z)
}
//Bir diğer kullanım
for(z in 0..3){ //0 dan 3 e kadar sıralar
println(z)
}
//Tabiki bunun yerine bunu da kullanabilirsiniz
myArrayOfNumbers.forEach{
println(it)
}
While
Kotlinde While C# daki for ile eşdeğer
var i = 0
while(i<10){
i++
println(i)
}
Fonksiyonlar
Fonksiyonlar c# daki metotlar ile eşdeğer dir Not: c# daki Void kotlindeki Unit e eşdeğerdir
fun mySum(a: Int,b: Int){ //Burda int değerde bir parametre istiyoruz
println(a+b)
}
//Sonrasında bunları onCreate da kullanıyoruz
mySum(a:20,b:10) //burda parametreyi giriyoruz
Peki bunu emulatör de gösterebilirmiyiz ?
Öncelikle Layout umuzda bir TextView oluşturuyor ve onun id sini alıyoruz.
fun mySum(a:Int,b:Int){
textView.text = "${a+b}" //text içerisinde yanlızca string değer atanabilir
//biz burda int değeri stringe çevirdik
}
//Sonrasında bunları onCreate da kullanıyoruz
mySum(a:20,b:10)
//Artık emülatör açıldığında 30 sayımızı textView de göstericek
//NOT: daha herhangi bir şey döndürmediği için bize Unit vericekdir
//void - Unit
Return (Fonksiyon döndürme)
Eğer ben bir fonksiyonu başka bir değişkene atamak istiyorsam zorunlu olarak o fonksiyonu geriye döndürülebilir kılmalıyım
//Burda yaptığımız : Int anlamı Int bir değer döndürceğiz demek
fun myMultiply(x:Int,y:Int): Int {
return x * y
}
//onCreate
val result = myMultiply(a:10,b:5)
textView.text = result.toString()
Görünümler ve Fonksiyonlar
/*view: View anlamı bir görünüm tarafından kullanılacak bir fonksiyon
Fonksiyonu farklı bir fonksiyonda kullanmamıza gerek yok çünkü zaten Layout
da kullanıyoruz */
fun clicked(view: View){ //clicked button un onClick id si
button.setOnClickListener{
println("bana tıkladın"),
}
}
OOP
Sınıf(Class)
Sınıflar nesne özelliklerine sahip değişken ve metodların bulunduğu yapılardır. Sınıflar nesne tabanlı programlama kullanan her programlama dilinde kullanılabilir. Sınıf ile nesne aynı yapılar değildir. Sınıf nesne özelliklerini tutan soyut (abstract) ifadelerdir. Sınıf ve nesne birbirine bağlıdır ama aynı kavramlar değildir. Bunu unutmamak gerekir.
Constructor
Sınıf çağırıldıkdan sonra oluşturulacak herhangi bir nesne için constructor çağrılır. Aynı şekilde bir sınıfın isteklerini meslse AgeInput veya NameInput
constructor(ageInput: Int, nameInput: String, jobInput: String){
this.age = ageInput /*ageInput class objesi oluşturulurken iste
ve bunu age ile eşitle */
this.name = nameInput
this.job = jobInput
//this içinde bulunduğu sınıfa veya bir üst seviyeye referans verir
}
/*Bundan sonra class dan obje çekildiği zaman değerleri parametre
üzerinden vermelisiniz*/
var homer = Simpson(ageInput: 50,nameInput:"Homer Simpson",jobinput"Nuclear")
**//Daha basit bir kullanım ise**
class Simpson(var name:String,var age:Int,var job:String) {
}
//MainActivity
var sim = Sipmson(name="Escan",age="15",job="student")
//şeklinde de kullanabilirsiniz
Access Modifier
- private = sadece tanımlandığı sınıf içerisinde kullanılabilir
- protected = private gibi sadece kalıtım aldığımız sınıfda da kullanılabilir
- internal = bütün projeden ulaşılır sadece bazı modüllerde ulaşılamaz
- public = her yerden ulaşılabilir
//Örnek classımız üzerrinden gidicem
class Simpson(var name:String,var age:Int,var job:String) {
private var hairColor = ""
}
//MainActivity
var homer = Simpson(ageInput: 50,nameInput:"Homer Simpson",jobinput"Nuclear")
homer.hairColor = "yeşil" //Artık bunu kullanamayız bize hata vericekdir
Peki biz bunu Private kullanmak isteseydik nasıl kullanırdık
//Örnek classımız üzerrinden gidicem
class Simpson(var name:String,var age:Int,var job:String) {
private var hairColor = ""
fun changeHairColor(){
this.hairColor = "yellow"
}
}
//MainActivity
var homer = Simpson(ageInput: 50,nameInput:"Homer Simpson",jobinput"Nuclear")
homer.changeHairColor() //fonksionumuz public olduğu için onu kullanabildik
Getter,Setter (Accees Modifier)
class Musician(name: String, instrument: String, age: Int) {
//encapsulation
//Burda name i değiştiremeyiz fakat çağırabiliriz james.name.ToString() gibi
var name : String? = name
private set
get
private var instrument : String? = instrument
//Burda age i değiştiremeyiz fakat çağırabiliriz james.age.ToString() gibi
var age : Int? = age
get
// age in değiştirilmesi sadece sınıf içerisinde geçerli olur
private set
}
Inheritence
//Biz bunu bir class a kalıtım olarak eklemek istediğimizde Musician ımıza open belirteci ekler
open class Musician(name:String,age:Int){
var name:String? = name
var age:Int? = age
}
class SuperMusician(name: String, age: Int) : Musician(name, age) {
fun sing() {
var lars = SuperMusician("Ahmet",22) // Artık Musician ı Super Musician da kullanabilirim
printin("nothing else matters")
}
}
Polymorphism
Aynı sınıf içerisinde aynı ismi kullanan metotları veya fonksiyonları kullanma
Static Polymorphism
class Mathematics {
fun sum() : Int {
return 0
}
fun sum(x : Int, y: Int) : Int {
return x + y
}
fun sum (x: Int, y:Int, z: Int): Int{
return x+y+z
}
}
//MainActivity
//Bu şekilde kullanabilirim
var mathematic = Mathematics()
println(mathematic.sum(10)
println(mathematic.sum(10,20))
println(mathematic.sum(10,20,30))
Dynamic Polymorphism
open class animal{
open fun sing(){
println("animal class")
}
}
class Dog: Animal{
//Sing fonksiyonumuzun üzerine yazdık yani Dog çağrıldığında Dog class gelicek
override fun sing(){
println("Dog class")
}
//super kalıtım aldığımız sınıfa referans verir
fun test(){
//Burda çağırdığımız sin animal class ındaki olucak
super.sing()
}
}
//MainActivity
val animal = Animal()
animal.sing()
val barley = Dog()
//Aslında animal.sing() in aynı çıktısını vericek
barley.test()
//override edilmiş fonskiyonu getiricek
barley.sing()
Abstract
Abstarct bizim bir obje oluşturamayacğımız bir sınıftır genelde kalıtım olarak alınması için kullanılır örnek Animal,People veya Generic gibi kullanılırlar Interface den farkı sadece tek bir class kalıtım alabilir
abstract class People{
fun information():String {
return "We are people"
}
}
class User: People{
fun test():String{
return "Me To"
}
}
//MainActivty
//Diyerek We are people yazdırabilirsiniz
println(myUser.information());
//Fakat interface veya abstract bir class ı çağıramazsınız
println(People.informatin()); //Hata verir
Interface
Abstract ile aynı işe yarar artı olarak istediğiniz kadar kalıtım aldırabilirsiniz
interface HouseDecor{
var roomName:String
}
interface Insturment{
fun info(){
println("instrument info")
}
}
class Piano: HouseDecor, Insturment{
var brand: String? = null
var digital: Boolean? = null
override var roomName:String
get() = "Kitchen"
set(){}
}
//MainActivty
var myPiano = Piano()
myPiano.brand ="Yamaha"
myPiano.digital = false
println(myPiano.roomName)
myPiano.Info()
Lambda
Örnek 1:
fun printString(myString:String){
println(mystring)
}
printString("My Test String")
//Bunu tek satırda yazamazmıyım Lambda ile yazarsın
//Bu şekilde tek satırda yazabilirsin
val testString = {myString: String -> println(myString)}
testString("My Lambda String")
Örnek 2:
val multiplyLambda = {a:Int,b:Int -> a * b}
println(multiplyLambda(5,10))
//Bir diğer kullanımı
//Bu şekilde de kullanılabilir
val multiplyLambda2:(Int,Int) -> Int = {a,b -> a*b}
println(multiplyLambda2(5,10))
İleri Seviye Lambda
Asynchrnous (Asenkron) (Completion)
Bir işlem yaparken uygulamamızı dondurmaz ve başka bir işlem yapmaya izin verir diyelimki internetten veri çekerken uygulamamızı dondurmaz
//Musician sınıfından Unit döndür
fun Download(url:String, completion: (Musician) -> Unit){
//Yükleme yapıldıktan sonra çağır
val kirkHamet = Musician("Kirk","Guitar",60)
completion(kirkHamet)
}
Download("escan.com",{musician ->
println(musician.name)
})
Synthetic Binding
Öncelikle Görseller ile oynama yapmadan önce ufak bir ayarlama yapmalıyız proje ayarlarımızdan Gradle Scripts>Build.gradle 2. sıradakine tıklayın ardından şu kodları yazın
// Bu kodu silip onun yerine
plugins{
id 'com.android.application'
id 'kotlin-andorid'
}
//Bu kodu ekleyin
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
fun clicked(){
textView.text = "Merhaba"
}
//Artık bu şekilde çok kolay bir şekilde görseller ile oynayabiliriz
- Eğer biz yukarıdaki ayarlamaları yapmasayadık mecburen bir TextView işlemi yaparken bile id yi bulmamız gerekicekdi örnek:
fun clicked(){
val textView = FindViewById<TextView>(R.id.text)
textView.text = "Merhaba"
}
Android View Binding
Kaynak: https://developer.android.com/topic/libraries/view-binding
Öncelikle ViewBinding i aktif etmeliyiz öncelikle aynı işlemleri birdaha yapalım Gradle Scripts>Build.gradle 2. sıradakine tıklayın ardından şu kodları yazın
//Öncelikle burda ufak bir değişiklik yapıcaz
android{
compileSdkVersion 30
buildToolsVersin "30.0.2"
defaultConfig {
applicationId "com.escan.viewbindingkotlin"
minsdkversiori 23
targetSdkversion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
compileOptions {
sourceCompatibility JavaVersion. VERSION_1_8
targetCompatibility Javaversion. VERSION_1_8
kotlinOptions {
jvmTarget = '1.8'
//Buraya Android in en altına
buildFeatures {
viewBinding true
}
}
Bu işlemleri yaptıktan sonra Build>ReBuild yaparak kotlin in bize hazır class ları kurmasını sağlayabiliriz fakta ekstra olarak birkaç değişken oluşturmalısınız
//lateinit = geç başlatmaya yarıyor sen başlatana kadar bellek yemiyor
private lateinit var binding: ActivityMainBinding
//ActivityMaingBindin ise proje admızın import kısmından bakabilirsiniz
import com.escan.viewbindingkotlin.databinding.ActivityMainBinding
/*Bundan sonra program projenizi bir kerelik aşağıdaki ayarlar ile
çalıştırmanızı istiyor*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//Proje adınızı girmeyi unutmayın
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root //Layout ile çalışacağımız belirtiyor
setContentView(view)
}
//Artık bu şekilde kullanabilirsiniz
fun isimDegis(view:View){
binding.textView.text = "Merhaba"
}
Data Binding
Gradle Scripts>Build.gradle 2. sıradakine tıklayın ardından şu kodları yazın
android{
compileSdkVersion 30
//Buraya Android in en altına
buildFeatures {
dataBinding true
}
buildToolsVersin "30.0.2"
defaultConfig {
applicationId "com.escan.viewbindingkotlin"
minsdkversiori 23
targetSdkversion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
compileOptions {
sourceCompatibility JavaVersion. VERSION_1_8
targetCompatibility Javaversion. VERSION_1_8
kotlinOptions {
jvmTarget = '1.8'
}
Bu işlemleri yaptıktan sonra Build>ReBuild yaparak kotlin in bize hazır class ları kurmasını sağlayabiliriz sonrasında xml imize gelip Layour umuzun üstüne birdaha Layout oluşturmalıyız
<Layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="132dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</Layout>
Peki Activity mizde buna nasıl ulaşıcaz
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this,R.layout.activity_main)
}
//Artık bu şekilde kullanabilirsiniz
fun isimDegis(view:View){
binding.textView.text = "Merhaba"
}
Scope
Diyelim ki bir fonksiyonda oluşturduğumuz değişkenlerimiz olsun bunları farklı bir fonksiyonda nasıl kullanırız ?
// Bunun için birkaç fonksiyonda kullanacağınız değişkenleri
// MainActivity nin bir altına tanımlamanız gerek
fun clicked(view: View){
val name = binding.Name.text.toString() //Kullanıcının girdiği değerleri aldık
val age = binding.Age.text.toString().toIntOrNull()
val job = binding.Job.text.toString()
}
//Eğer bu şekilde çağırmak istersek bize hata verir
fun scopeExample(view:View){
println(name)
}
//Olması gereken
class MainActivity : AppCompatActivity() {
//Name,age,job değişkenelerimi burda tanımlıyıcam
var name = ""
var job = ""
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
fun clicked(view: View){
name = binding.Name.text.toString() //Kullanıcının girdiği değerleri aldık
var age = binding.Age.text.toString().toIntOrNull()
job = binding.Job.text.toString()
}
// Artık burda name çağırabilirsiniz clicked butonu yerine scopeExample a basarsak
// konsola name i yazdıracakdır
fun scopeExample(view:View){
println(name)
}
}
Veri Saklamak(Küçük boyutlar)
Shared Preferences
Veri Okumak ve Veri Kaydetmek
Küçük verileri Telefonda saklamak örneğin bir kişi hesap makinesinde bir işlem yapıyor ardından yanlışlıkla sonucu siliyor veya uygulamadan çıkıyor burada bu sonucun kaybolmaması için bir bellekte Telefon hafızasında tutmalıyız
class MainActivity : AppCompatActivity() {
//uygulama açıldığında saklı olan veriyi getirmek için
// bunu onCreate de de kullanmam lazım buyüzedn sharedPreferences ı burda aoluşturuyorum
lateinit var sharedPreferences: SharedPreferences
var ageFromPreferences : Int? = null
**** override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//İlk parametrede verilerin cihazımızda hangi isimle tutulacağını yazıyoruz.
//Mesela ben com.escan.verisaklamak kullandım. İkinci değer’e ise Context.MODE_PRIVATE yazıyoruz,
//bunu yazmamızın sebebi dışarıdan erişilmesini engellemek ve güvenli hale getirmek.
sharedPreferences = this.getSharedPreferences("com.escan.verisaklamak",
Context.MODE_PRIVATE)
//birinci parametreye sakladığımız key’in adını,
// ikinci parametreye ise eğer öyle bir key yoksa geriye döndüreceği
//default değeri yazıyoruz.
//Veri okuma kısmı
ageFromPreferences = sharedPreferences.getInt("Age",0)
if (ageFromPreferences == 0){
textView.text = "YourAge:"
}
else{
textView.text = "YourAge:${ageFromPreferences}"
}
}
//EditText
fun Save(view: View){
var dataAge = EditText.text.toString().toInt()
textView.text = "Your age: ${dataAge}"
sharedPreferences.edit().putInt("Age",dataAge).apply()
}
}
Verileri silmek
class MainActivity : AppCompatActivity() {
lateinit var sharedPreferences: SharedPreferences
var ageFromPreferences : Int? = null
**** override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sharedPreferences = this.getSharedPreferences("com.escan.verisaklamak",
Context.MODE_PRIVATE)
ageFromPreferences = sharedPreferences.getInt("Age",0)
if (ageFromPreferences == 0){
textView.text = "YourAge:"
}
else{
textView.text = "YourAge:${ageFromPreferences}"
}
}
//EditText
fun Delete(view: View){
ageFromPreferences = sharedPreferences.getInt("Age",-1)
if (ageFromPreferences != -1){
sharedPreferences.edit().remove("Age").apply()
textView.text="Your age"
}
}
Intent (Farklı ekranlar ekleme)
Öncelikle intent bir Activity dir app>java>com.escan.ProjeAdı>sağ tıklayın>New>Activity>Galery>Görünüm seç ve aktar artık ikinci bir sayfamız oldu isterseniz tekrardan farklı bir tasarım verebilirsiniz veya o sayfaya özel kodlarınızı yazabilirsiniz peki ben bir butona basınca nasıl sayfa değiştiricem ?
//Sayfa1 de yazdığımız kod
fun clicked(view: View){
//Sayfa2 = MainActivity2
val intent = Intent(applicationContext,MainActivity2::class.java)
startActivity(intent)
}
//Buton = clicked
Verileri 2. ekrana aktarma
fun clicked(view: View){
val intent = Intent(applicationContext,MainActivity2::class.java)
//name keyi ile Name id sindde verilen değeri yolladık
intent.putExtra("name",Name.text.toString())
//surname keyi ile Surname id sinde verilen değeri yolladık
intent.putExtra("surname",Surname.text.toString())
startActivity(intent)
}
//Bunu diğer sayfada tutmak için
//Sayfa2
class MainActivity2 : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
//Sayfa açılırken 1. sayfadan buraya yollanan intentleri tuttuk
val intent = intent
val name = intent.getStringExtra("name");
val surname = intent.getStringExtra("surname");
textView.text = "${name + surname}"
}
}
Activity Lifecycle
Not: Eğer biz bir Activiteyi kapatmaz isek bu arkada güç harcayacakdır buda uygulamamızın performansını düşürür bunun için finish() ile aktivitelerimizi kapatman bizim için en iyisi olacakdır.
//-----Activity Lifcycle-----//
//Oluşturur
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
//Oluşturulduktan sonra çalışır
override fun onResume() {
super.onResume()
println("On Resume Called")
}
//Diğer aktiviteye giderken çalışır veya uygulama kapandığında tekrar açıldığında çalışmaz
override fun onPause() {
super.onPause()
println("On Pause Called")
}
//aktivite çalıştıkdan sonra kendisi çalışır ve onResume geri dönderir
override fun onStop() {
super.onStop()
println("On Stop Called")
}
//Activity kapatıldığında verir
override fun onDestroy() {
super.onDestroy()
println("On Destroy Called")
}
//-----Activity Lifcycle-----//
//Activity başlatıldıkdan sonra kapatılmaz ise uygulama yavaşlar
fun clicked(view: View){
val intent = Intent(applicationContext,MainActivity2::class.java)
intent.putExtra("name",Name.text.toString())
intent.putExtra("surname",Surname.text.toString())
startActivity(intent)
//Activity kapatır böylelikle bize performans sağlar
finish()
}
Google Play’e yüklemek
İmzalı apk yükleyin:
Uyarı Mesajı
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Toast.makeText(applicationContext,"Welcome",Toast.LENGTH_LONG).show()
}
fun clicked(view:View){
val alert = AlertDialog.Builder(this)
alert.setTitle("Save")
alert.setMessage("Are you sure")
//Kullanıcı pozitif butona basınca ne yapacak
alert.setPositiveButton("Yes",){dialog, which ->
//OnClick listener yes alert ına basıldığı zaman saved yazar
Toast.makeText(applicationContext,"Saved",Toast.LENGTH_LONG).show()
}
alert.setNegativeButton("No"){dialog, which ->
//OnClick listener yes alert ına basıldığı zaman saved yazar
Toast.makeText(applicationContext,"Not Saved",Toast.LENGTH_LONG).show()
}
alert.show()
}
}
Context Nedir
Context
Activity Context → this
this aktiviteyle ilgili durumlarda kullanılır eğer siz MainActivity e referans vermek isterseniz ve this bunu vermez ise this@MainActivity şeklinde kullanabilirsiniz
App Context → applicationcontext
appilcationcontext genel uygulama ile ilgili örnek toast işlemi yaparken applicationcontext kullanabilirsiniz
CountDownTime
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun clicked(view: View){
//MyTimer adında bir obje oluştur bu CountDownTimer dan kalıtım alan bir nesne olsun
object : CountDownTimer(60000,1000){
//her bir belirtilen periyotda ne olucak
override fun onTick(p0: Long) {
textView2.text = "${p0/1000}"
}
//işlem bittiğinde ne olucak
override fun onFinish() {
textView2.text = "0"
}
}.start()
}
}
Kronometre yapımı
class MainActivity : AppCompatActivity() {
var number = 0
lateinit var runnable : Runnable
var handler: Handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun Start(view:View){
number = 0
runnable = object:Runnable{
override fun run() {
number = number + 1
textView.text = "$number"
handler.postDelayed(this,1000)
}
}
handler.post(runnable)
}
fun Stop(view:View){
handler.removeCallbacks(runnable)
number = 0
textView.text = "0"
}
}
RecyclerView
Önce nedir bu recyclerview, ne yapar ondan bahsedelim. Verileri listelemek için kullanılan bir yapıdır. Scroll (kaydırma) işleminin yapılmasını sağlar
Adapter
Adapter verileri RecyclerView’e bağlar. Verileri bir ViewHolder içinde görüntülenebilecek şekilde uyarlar. RecyclerView, verilerin ekranda nasıl görüntüleneceğini anlamak için adapter kullanır.
→ onCreateViewHolder( ): Adapter oluşturulduğunda ViewHolder’ı başlatıyor.
→ getItemCount( ): Listemizin eleman sayısını veriyor.
→ onBindViewHolder( ) : onCreateViewHolder’dan dönen verilerin bağlama işlemini gerçekleştiriyor.
LayoutManager
Bu nesne RecyclerView’in itemlerini konumlandırır ve ekran dışında geçiş yapan itemlerin ne zaman geri dönüştürüleceğini söyler.
Default olarak Layout Manager 3 seçenek sunar.
→ LinearlayoutManager : İtemleri standart ListView şeklinde görünmesini sağlar.
→ GridLayoutManager : İtemlerin satır ve sütun şeklinde görünmesini sağlar.
→ StaggeredGridLayoutManager : İtemlerin kademeli satır ve sütun şeklinde görünmesini sağlar.
ViewHolder (RecyclerView)
Her itemin içinde bulunan bileşenlerin tanımlama işleminin yapıldığı yerdir.
Tasarımı oluşturalım (RecyclerView)
- Öncelikle recycler_row adında bir layout oluşturalım
- içerisine CardView imizi veya istediğimiz tasarımı yapalım verilerin bize nasıl gözükmesini istiyorsak ben bir CardView oluşturdum
- activity_main tasarımımıza recyclerView i atalım ve heigt ve width ine match parent verelim ve contraint ini ekleyelim
Adapter oluşturma (RecyclerView)
//Ulkeler adında bir data class oluşturulaım
data class Ulkeler(var ulkeNo:String,var ulkeAdi:String){
}
//Adapter adında bir kotlin class oluşturalım
class Adapter(private val context:Context,private val ulkeler:List<Ulkeler>):RecyclerView.Adapter<Adapter.CardViewHolder>{
//inner class iç sınıf anlamına geliyor sınıf içi sınıf oluştururken kullanıyoruz
inner class CardViewHolder(view:View):RecyclerView.ViewHolder(view){
var satirCardView: CardView
var satirYazi:TextView
var noktaResim:ImageView
//init yani constructor
init{
satirCardView = view.findViewById(R.id.satirCardView)
satirYazi = view.findViewById(R.id.satirYazi )
noktaResim = view.findViewById(R.id.noktaResim )
}
}
override fun onCreateViewHolder(parent:ViewGroup,viewType:Int):CardViewHolder{
var itemView = LayoutInflater.from(context).inflate(R.layout.recycler_row,parent,false)
return CardViewHolder(itemView)
}
override fun onBindViewHolder(holder: CardViewHolder,position:Int){
val ulke = ulkeler[position]
holder.satirYazi = ulke.ulkeAdi
holder.satirCardView.setOnClickListener{
Toast.makeText(context,"Ülke: ${ulke.ulkeAdi}",Toast.LENGTH_LONG).show(){
}
override fun getItemCount():Int{
return ulkeler.size
}
}
MainActivity içeriği (RecyclerView)
private lateinit var ulkelerList:ArrayList<Ulkeler>
private lateinit var adapter:Adapter
//onCreate alanı {
recyclerView.layoutManager = LinearLayoutManager(this)
val u1 = Ulkeler(1,"Türkiye")
val u2 = Ulkeler(2,"Almanya")
val u3 = Ulkeler(3,"ABD")
val u4 = Ulkeler(4,"Isviçre")
ulkelerList = ArrayList<Ulkeler>()
ulkelerList.add(u1)
ulkelerList.add(u2)
ulkelerList.add(u3)
ulkelerList.add(u4)
adapter = Adapter(this,ulkelerList)
// }
Menu yapımı
Öncelikle tasarım için Layout dan bir Resource file oluşturalım ardından xml kısmından bu kodlar ile bir menu oluşturlarım xml ile yapmak daha basit olduğundan menu yü xml ile yapmanızı öneririm
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/add_art"
android:title="Add Art">
</item>
</menu>
Bize 3 nokta ya basınca Add Art kutucuğu çıkaran bir menü geldi şimdi bunu nasıl kullanıcaz MainActivity mize gelelim zaten bunlar override edilmesi gereken hazır fonksiyonlar biz burda gelip bunları override ediyoruz
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
//inflater xml ile activity mizi bağlıcağımız zaman kullanırız
val menuInflater = menuInflater
menuInflater.inflate(R.menu.artmenu,menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
//item.itemId = Kullanıcının tıkladığı id
if (item.itemId == R.id.add_art){
val intent = Intent(MainActivity@this,DetailsActivity::class.java)
startActivity(intent)
}
return super.onOptionsItemSelected(item) //itemi döndür
}
İzin Yönetimi (Permissions)
Kullanıcıdan erişeceğimiz yelerin iznini almak zorundayız bu uygulamamızın güvenirliğini arttırır bunun için android in kendi sitesinden bunu nasıl yapıcağınıza bakabilirsiniz.
Bunun için öncelikle protected seviyesi yüksek olan örnek ReadExternalStorage yani kişinin galerisine giriş izni verir bu tarz durumlarda manifests den bunu packages hemen altına eklemeliyiz
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
Peki bunu Activity mizde nasıl kullanıcaz işte böyle:
class DetailsActivity : AppCompatActivity() {
private lateinit var binding: ActivityDetailsBinding
private lateinit var activityResultLauncher: ActivityResultLauncher<Intent>
private lateinit var permissionLauncher: ActivityResultLauncher<String>
var selectedBitmap: Bitmap? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDetailsBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
registerLauncher()
}
fun saved(view: View){
}
fun selectImage(view: View){
//Kullanmamıza izin verdiyse
if(ContextCompat.checkSelfPermission(this,android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager. PERMISSION_GRANTED){
//ACTION_PICK ile gidip alıyoruz anlamına geliyor Action larda tüm izinler için farklı kullanımlar var örnek BATTERY_LOW gibi
// MediaStore.Images.Media.EXTERNAL_CONTENT_URI ise galeri ye gider ve kullanıcının seçtiği fotoğrafı alır
val intentToGalery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activityResultLauncher.launch(intentToGalery)
}
else{
//Rationale (rasyonel)
//Kullanıcıya izin alma mantığını göstereyimmi
if (ActivityCompat.shouldShowRequestPermissionRationale(this,android.Manifest.permission.READ_EXTERNAL_STORAGE)){
Snackbar.make(view,"Permission needed for gallery",Snackbar.LENGTH_INDEFINITE).setAction("Yes",View.OnClickListener {
permissionLauncher.launch(android.Manifest.permission.READ_EXTERNAL_STORAGE)
}).show()
}
else{
//Request Permission (Kullanıcıdan izin almadan yapar)
permissionLauncher.launch(android.Manifest.permission.READ_EXTERNAL_STORAGE)
}
}
}
private fun registerLauncher(){
activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->
if (result.resultCode == RESULT_OK){
val intentFromResult = result.data
if (intentFromResult != null){
val imageData = intentFromResult.data
if (imageData != null){
println("Photos Download")
try {
if (Build.VERSION.SDK_INT >= 28){
val source = ImageDecoder.createSource(this@DetailsActivity.contentResolver,imageData)
selectedBitmap = ImageDecoder.decodeBitmap(source)
binding.imageView.setImageBitmap(selectedBitmap)
}else{
selectedBitmap = MediaStore.Images.Media.getBitmap(contentResolver,imageData)
binding.imageView.setImageBitmap(selectedBitmap)
}
}catch (e:Exception){
e.printStackTrace()
}
}
}
}
}
permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){result ->
if (result){
//permission Granted
val intentToGalery = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activityResultLauncher.launch(intentToGalery)
}else{
//permission Denied
Toast.makeText(this@DetailsActivity,"Permission Needed",Toast.LENGTH_LONG).show()
}
}
}
}
Room Database
Room aslında Sql Lite ile aynı şey tek fark normal yazdığınız Sql kodları yerine burda Room kodları yazıyoruz
Kaynak: https://developer.android.com/training/data-storage/room
Öncelikle Gradle ımızda ufak bir ayarlama yapmalıyız Gradle Scripts >2. gradle> ardından Dependecies alanında şu kodları girin
dependencies {
var roomVersion = "2.4.2"
implementation("androidx.room:room-runtime:$roomVersion")
annotationProcessor("androidx.room:room-compiler:$roomVersion")
// To use Kotlin annotation processing tool (kapt)
kapt("androidx.room:room-compiler:$roomVersion")
implementation("androidx.room:room-rxjava3:$roomVersion")
implementation "io.reactivex.rxjava3:rxandroid:2.4.2"
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'com.google.android.gms:play-services-maps:17.0.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
Sonrasında Plugins alanımdan gerekli id yi eklemeliyiz
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
Room Arcitecture
Room kullanımı
Öncelikle 4 adet klasör ekliyeceğiz
MainActivitymizi View içerisine atıyoruz
Entities
Sonrasında model içerisine Place adında bir class oluşturuyorum
@Entity
class Place(
//Kolonları ayarladık
@ColumnInfo(name = "name")
var name:String,
@ColumnInfo(name = "latitude")
var latitude:Double,
@ColumnInfo(name = "longitude")
var longitude:Double) {
//Otomatik olarak id yi arttırır
@PrimaryKey(autoGenerate = true)
var id = 0
}
Data Access Object (DAO)
roomdb klasörümüzde PlaceDao diye oluşturduk ve içerisine kodlarımızı yazdık
@Dao
interface IPlaceDao {
@Query("SELECT * FROM Place")
fun GetList(): List<Place>
@Insert
fun insert(place: Place)
@Delete
fun delete(place: Place)
}
Database
Burda da database imizi oluşturuyoruz aynı şekilde roomdb ye oluşturuyoruz
@Database(entities = arrayOf(Place::class), version = 1)
abstract class PlaceDatabase:RoomDatabase() {
//IPlaceDao İçerisindeki insert gibi metotlar bulunuyor
abstract fun placeDao():IPlaceDao
}
MainActivity de çağırmak
//Öncelikle nesneleri oluşturuk
private lateinit var db : PlaceDatabase
private lateinit var placeDao: IPlaceDao
fun Save(view: View){
val place = Place(binding.placeText.text.toString(),selectedLatitude!!,selectedLongitude!!)
//Nesnemizi database e aktardık
placeDao.insert(place)
}
//Fakat bize hata vericekdir bunu çözmek için ise RxJava adında bir library eklememiz lazım
RxJava
implement eklemek için:
implementation "io.reactivex.rxjava3:rxjava:2.4.2"
val compositeDisposable: CompositeDisposable()
fun Save(view: View){
val place = Place(binding.placeText.text.toString(),selectedLatitude!!,selectedLongitude!!)
compositeDisposable.add(
placeDao.insert(place)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleResponse)
)
}
private fun handleResponse(){
val intent = Intent(this,MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(intent)
}
PlaceDao sayfamız
//Bize asenkron bir yapı sunar
@Dao
interface IPlaceDao {
@Query("SELECT * FROM Place")
fun GetList(): Flowable<Place>
@Insert
fun insert(place: Place):Completable
@Delete
fun delete(place: Place):Completable
}
Navigation Component
Navigation Component Nedir ?
Sayfa geçişlerini daha görsel ve pratik hale getiren bir yapıdır. • Activity üzerinde istediğimiz şekilde fragment geçişleri yapabiliriz. • Geçişlerde veri transferi yapabiliriz. • Geçişlere animasyon ekleyebiliriz. • Birden fazla activityde kullanılabilir ama her activity için ayrı navigation dosyası oluşturmalıyız
Kurulum için
gradle>build.gradle>dependecies{
implementation "androidx.navigation:navigation-fragment-ktx:2.3.3" implementation "androidx.navigation:navigation-ui-ktx:2.3.3"
}
Navigation Klasörü Oluşturma
res klasörümüze sağ tıklayıp Android Resource Directory tıklayın navigation adını verin ResurceType: navigation seçin ardından oluşturun. Ardından navigation dosyamıza sağ tıklayıp Navigation Resource File diyin file name: main_activity_nav sonrada oluşturun
Fragment Oluşturma
MainActivity mizin bulunduğu dosyaya sağ tıklayın new>fragment>fragment(blank)>finish
sonrasında kodda düzenleme yapalım:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val tasarim = inflater.inflate(R.layout.fragment_anasayfa, container, false)
tasarim.buttonBasla.setOnClickListener{
}
return tasarim
}
Navigation Component’e fragment ekleme
main_activity_nav navigation ımıza geliyoruz tam ortaya basıyoruz ardından teker teker fragment larımızı sürüklüyoruz
Not: Ana fragment eklemek için onunu üzerine ev işaretini eklemelisiniz
Fragment Arası Geçiş Bağlantısı Oluşturma
Öncelikle Navigation ımızda sayfaların sağında çıkan bağlama boloncuklarından bu şekilde bağlıyoruz ve bu bağlamalara birer id veriyorum
Pekala bağlama işlemini yaptık diyelim bundan sonraki işlem bu butonlara bu sayfa geçiş kodlarını girmeliyiz:
class AnasayfaFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val tasarim = inflater.inflate(R.layout.fragment_anasayfa, container, false)
tasarim.buttonBasla.setOnClickListener{
//it butonu temsil ediyor
Navigation.findNavController(it).navigate(R.id.oyunEkraninaGecis)
}
return tasarim
}
}
//Aynısını OyunFragment içinde yapıyoruz bu sefer gidilcek sayfa olarak sonucFragment seçiyouz
Navigation Component Back Stack
Bu işlemin Active Directory deki karşılığı finish() dir.
Navigation sayfamıza geliyoruz OyunEkranından Sonuç ekranına geçişimizi sağlayan oka tıklıyoruz ve bir popUpTo ekliyoruz burda sonuc ekranına geçilidğinde arkadaki hangi işlemi silelim demiş oluyoruz ve bukadar basit
//Notlar Tamamen Escan Dönmez'e aittir
Navigation Component Veri Transferi
Not: Eğer yani android sürümünü kullanyorsanız bu linkden yardım alın
Navigation'da Safe Args ile Ekranlar Arası Veri Paylaşımı (mobiler.dev)
Öncelikle kurlumu yapalım build.gradle(module) gidelim ve bu implementasyonu yapalım
apply plugin: "androidx.navigation.safeargs.kotlin"
Ardından build.gradle(project) gidelim ve orayada bu implamanyasyonu yapalım
dependecies{
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.3"
}
Peki bu işlemi nasıl yapıcaz öncelikle navigation ımıza geliyoruz ve verilerin gönderileceği sayfanın üstüne tıklıyoruz
burdaki gibi gönderilecek verileri seçmemiz lazım //Notlar Tamamen Escan Dönmez'e aittir
Eklediğimiz implamantasyonlar sonucunda otomatik Directions sınıfı oluştu bunun sayesinde oluşturduğumuz argümanlara veri gönderebiliriz
var gonder = AnasayfaFragmentDirections.oyunEkraniFragment()
gonder.ad = "Escan"
gonder.boy = 177f
gonder.yas = 22
gonder.bekarMi = true
//burda arguments larımıza değer atadık
Navigation.findNavController(it).navigate(gonder)
//bizi gonder değişikenindeki fragment a gönderir ve bununla beraber içerisindeki argümankarları da yollar
Sonrasında bu veriyi OyunFragment ımızdan çekiyoruz //Notlar Tamamen Escan Dönmez'e aittir
//OyunEkraifragmentArgs veriyi alıcak sayfayı temsil eder
val bundle: OyunEkraniFragmentArgs by navArgs()
val gelenAd = bundle.ad
val gelenYas = bundle.yas
val gelenBoy = bundle.boy
val gelenBekarMi = bundle.bekarMi
println(gelenAd,gelenYas,gelenBoy,gelenBekarMi)
Navigation Draw
Sol tarafta sidebar şeklinde ortaya çıkan bir menü türüdür
Öncelikle Navigation ımızı kurmalıyız bunun için Navigation Component Kurulum başlığımıza gidebilirsiniz ardından iki adet de fragment oluşturun aynı şekilde themes gelip orda şu kodları yazarak menü yü kapatın:
//Notlar Tamamen Escan Dönmez'e aittir
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
- Öncelikle bir menü dosyası oluşturun
- menu resource file oluşturun
- içerisine iki adet menuItem ekleyin
Evet işte işin asıl püf noktası burda yapacağını şey Navigation’nınıza dönüp oluşturduğunuz iki fragment ın adlarına bakmanız olucak bu adları menünüzdeki item ların id leri ile aynı olmak ZORUNDA
- activiy_main.xml e gel
- Code alanında Constrait i DrawerLayout ile değiştir ve id olarak drawer verelim
- drawer’ın içerisine bir adet constrait oluşturalım
- constrait in içine bir adet toolbar koyalım
- ardından navHostFragment alıp sayfanın üstüne koyalım ve id olarak nav_host_fragment diyelim ki menü değişimlerinde sayfamızda bizimle gelsin
- sonrasında constrait layout umuzun altına Not:içine değil altına navigationView ekleyelim ve navigationView adında id verelim ve genişliğini wrap content yapalım
- navigationView in menu categorysin’e tıklayıp bizim menümüzü ekliyelim
- Code kısmına girip navigationView’e
android:layout_gravity="start"
bu kodu girerek sidebar şeklini almasını sağlayalım - aynı şekilde Code kısmında DrawerLayout un hemen altına bu kodu da girmeliyiz
tools:openDrawer="start"
//Notlar Tamamen Escan Dönmez'e aittir
Main Activity kodunu yazalım
öncelikle bağlamaları yapmalıyız fragment ımız ile menümüzü bağlamalıyız
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//nav_host_fragment ile navigationView i yani sidebar ı birbirine bağladık artık birinci ikinici diye kategori değiştirebilicez
var navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
NavigationUI.setupWithNavController(navigationView,navHostFragment.navController)
//Notlar Tamamen Escan Dönmez'e aittir
//drawer ile toolbarı birbirine bağladık
toolbar.title = "Başlık"
val toggle = ActionBarDrawerToggle(this,drawer,toolbar,0,0)
drawer.addDrawerListener(toggle)
toggle.syncState()
//Notlar Tamamen Escan Dönmez'e aittir
}
}
//Notlar Tamamen Escan Dönmez'e aittir
Geri Tuşu Yapıldığında Drawer(Sidebar) Kapanması
override fun onBackPressed() {
if(drawer.isDrawerOpen(GravityCompat.START)){
drawer.closeDrawer(GravityCompat.START)
}else{
super.onBackPressed()
}
}
Sidebar başlık ekleme
- Öncelikle Layout dosyamıza sağ tıklayıp Layout Resource File oluştruuyoruz navigation_baslik adında
- sonrasında constrait Layoutumuzda layout_weight’e 200 dp verelim ardından textView oluşturup üzerinde orantılıyalım ve constraintini ekleyelim
- bundan sonrası tamamen kodumuza kaldı hadi gelin kodumuzu yazalım
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
NavigationUI.setupWithNavController(navigationView,navHostFragment.navController)
//Notlar Tamamen Escan Dönmez'e aittir
toolbar.title = "Başlık"
val toggle = ActionBarDrawerToggle(this,drawer,toolbar,0,0)
drawer.addDrawerListener(toggle)
toggle.syncState()
//Başlık navigation tasarımımızla navigation ımızı bağlıyaağcağız
val baslik = navigationView.inflateHeaderView(R.layout.navigation_baslik)
baslik.baslik.text = "Başlık"
}
override fun onBackPressed() {
if(drawer.isDrawerOpen(GravityCompat.START)){
drawer.closeDrawer(GravityCompat.START)
}else{
super.onBackPressed()
}
}
Hazır fotoğraf yükleme thamplate
- Öncelikle web sitelerinden birine gidelim
- Picasso (square.github.io)
- web sitesinde de gördüğünüz implemente etme kodlarını görüyorsunuzdur gelin implemente edelim
- build gradle da module olanına giriyoruz dependecies alanına bu kodu yapıştırıyoruz
implementation 'com.squareup.picasso:picasso:2.71828'
Picasso.get().load(postList.get(position).downloadUrl).into(holder.binding.recyclerImageView)
Sorgu işlemleri
bir veriyi çekiceğimiz zaman sorgu ile çekebiliriz böylelikle tüm veryii getirmemize gerek kalmaz.
Örnek:
//escandöner@gmail.com getir sadece
.whereEqualTo("userEmail","escandöner@gmail.com")
//Score 200 den büyükse
.whereGreaterThan("Score",200)
//en yakın tarihleri getirir DESCENDİG aşağıdan yukarıya doğru gösterir
.orderBy("date",Query.Direction.Descending)
Coroutine ****
Uzun süreli işlemlerde örnek internetten veri çekerken resim çekerken Async gibi tasarımın donmasını engeller. Not= thread lere göre daha hafif bir yapıdır mesela 100 000 adet println yaptıracaksınız normalde bu tarz bir kod sistemi yavaşlatır fakat bunu coroutine ile sorunsuzca yapabiliriz
//Notlar Tamamen Escan Dönmez'e aittir
Global Scope
// Bütün bir application da kullanmamıza yarar
GlobalScope.launch {
repeat(100000){
launch {
print("Merhaba")
}
}
}
runBlocking
/*
İçerideki Coroutine işlemleri bitene kadar sonrasındaki kodların çalıştırılmasını durdurur
Gördüğünüz gibi ilk önce Coroutine içeriğini çalıştırıyor ondan sonra işlem tamamlandıktan sonra
Coruitine dışındaki işlemleri gerçekleştiriyor
*/
println("run blocking start")
runBlocking {
launch {
delay(5000)
println("runblocking")
}
}
println("run blocking end")
Coroutine Scope
/*
İçerideki bütün Coroutine ler bitene kadar çalışmaya devam eder
CoroutineScopeları sadece bir coroutine veya suspend functionların içerisinde çağırılabilir
Çıktı:
Coroutine start ve end ilk önce görünür ondan 5 sn sonrada coroutine içeriği görünür yani coroutine arka planda çalışır
*/
println("coroutine scope start")
//Dispatchers lar yazının devamında anlatıyorum
CoroutineScope(Dispatchers.Default).launch{
delay(5000)
println("coroutine scope")
}
println("coroutine scope end")
**//Coroutine iç içe kullanımda**
runBlocking {
launch {
delay(5000)
println("run blocking")
}
coroutineScope {
launch {
delay(3000)
println("Coroutine Scope")
}
}
}
Dispatcher lar
Dispatchers.Main -> UI
Tasarım ile ilgili durumlarda kullanılır
Dispatchers.IO -> Input Output, Networking
İnternetten birşey çekerken kullanılır
Dispatchers.Default -> Cpu Intensive
Uzun bir diziyi dizerken veya cpu nun yoğun kullanıldığı işlemlerde kullanılır
Dispatchers.Unconfined -> Inherited disppatcher
İçerisinde çalıştırılan yere göre kalıtım alıyor
//ÖRNEK
//Notlar tamamen Escan Dönmez'e aittir
runBlocking {
launch(Dispatchers.Main){
println("Main Thread: ${Thread.currentThread().name}")
}
launch(Dispatchers.IO) {
println("IO Thread: ${Thread.currentThread().name}")
}
launch(Dispatchers.Default) {
println("Default Thread: ${Thread.currentThread().name}")
}
launch(Dispatchers.Unconfined) {
println("Unconfined Thread: ${Thread.currentThread().name}")
}
}
/*
ÇIKTI:
Default Thread: DefaultDispatcher-worker-1
IO Thread: DefaultDispatcher-worker-2
Unconfined Thread: main
*/
Suspend Coroutine
funmain() {
runBlocking{
delay(2000)
println("run blocking")
myFunction()
}
}
suspend fun myFunction(){
coroutineScope{
delay(4000)
println("suspend function")
}
}
//Notlar tamamen Escan Dönmez'e aittir
/*Çıktı:
2sn
run blocking
4sn sonra
suspend function
*/
Job Nedir
fun main(){
runblocking{
val myJob = launch{
delay(2000)
println("job")
val secondJob = launch{
println("job2")
}
}
//Tüm işler bittikden sonra bunu yap
myJob.invokeOnCompletion{
println("Tüm işlemler bitti")
}
}
}
// Çıktı olarak bize ilk önce job job2 ve Tüm işlemrim bitti çalışır
//Notlar tamamen Escan Dönmez'e aittir
fun main(){
runblocking{
val myJob = launch{
delay(2000)
println("job")
val secondJob = launch{
println("job2")
}
}
myJob.invokeOnCompletion{
println("Tüm işlemler bitti")
}
myJob.cancel()
}
}
// Çıktı olarak Tüm işler bitti yi verir çünkü burda myJobu tamamen bitirdik
withContext nedir
fun main(){
runblocking{
launch(Dispatchers.Default){
println("Context: ${coroutineContext}")
withContext(Dispatchers.IO){
println("Context: ${coroutineContext}")
}
}
}
}
Work Manager
Kısaca mantığı uygulama kapatılsa bile çalışmaya devam etmesi
//İmplementasyon
dependencies {
implementation("androidx.work:work-runtime-ktx:2.7.1")
}
Worker sınıfı
Refresh database adında bir class oluşturularım class a Worker kalıtımı veriyorum ve interface elemanlarını implemente ediyorum
class RefreshDatabase(val context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) {
override fun doWork(): Result {
val getData = inputData
val myNumber = getData.getInt("intKey",0)
refereshDatabase(myNumber)
return Result.success()
}
private fun refereshDatabase(mysNumber:Int) {
val sharedPreferences = context.getSharedPreferences("com.escan.workmanager",Context.MODE_PRIVATE)
var myNumber = sharedPreferences.getInt("myNumber",0)
myNumber = myNumber + mysNumber
println(myNumber)
val editor = sharedPreferences.edit()
editor.putInt("myNumber",myNumber).apply()
}
//Notlar tamamen Escan Dönmez'e aittir Sonrasında Main Activity e gelelim
val data = Data.Builder().putInt("intKey",1).build()
val constraints = Constraints.Builder()
//İnternet bağlıyken sadece çalışır
//.setRequiredNetworkType(NetworkType.CONNECTED)
//sadece şarz da değilken çalışır
//.setRequiresCharging(false)
.build()
//Tek seferde çalışır
//OneTimeWorkRequestBuilder<>()
val myWorkRequest :WorkRequest = OneTimeWorkRequestBuilder<RefreshDatabase>()
.setConstraints(constraints)
.setInputData(data)
.build()
WorkManager.getInstance(this).enqueue(myWorkRequest)
//periyodik şekilde belli dakikalar la çalışır
//PeriodicWorkRequestBuilder<>()
val myWorkRequestPeriodic : PeriodicWorkRequest = PeriodicWorkRequestBuilder<RefreshDatabase>(15,TimeUnit.MINUTES)
.setConstraints(constraints)
.setInputData(data)
.build()
WorkManager.getInstance(this).enqueue(myWorkRequestPeriodic)
Gözlemleme ve Zincirleme (WorkManager)
//Notlar tamamen Escan Dönmez'e aittir
//Chaining
val oneTimeRequesta: OneTimeWorkRequest = OneTimeWorkRequestBuilder<RefreshDatabase>()
.setConstraints(constraints)
.setInputData(data)
.build()
WorkManager.getInstance(this)
//Bununla başla
.beginWith(oneTimeRequesta)
//Ardından bunu yap
.then(oneTimeRequesta)
//Ardından bunu yap
.then(oneTimeRequesta)
.enqueue()