Kotlin ile Not Uygulaması Yapımı

Yönetici

Bu rehberde, Kotlin programlama dili kullanarak Android için basit bir not alma uygulaması geliştireceğiz. Uygulama, kullanıcıların not eklemesine, düzenlemesine, silmesine ve liste halinde görüntülemesine olanak tanıyacak. Ayrıca, verileri kalıcı olarak saklamak için Room veritabanını kullanacağız.

Geliştirme Ortamı Kurulumu​

Başlamadan önce aşağıdaki araçlara ihtiyacınız olacak:
  • Android Studio: En son sürüm (örneğin, 2023.3.1 veya üstü).
  • Kotlin: Android Studio ile varsayılan olarak gelir.
  • Gradle: Proje bağımlılıklarını yönetmek için.
Android Studio’yu kurduktan sonra yeni bir proje oluşturun:
  1. Empty Activity şablonunu seçin.
  2. Dil olarak Kotlin’i seçin.
  3. Minimum API seviyesini API 21 (Lollipop) olarak ayarlayın.

Proje Yapısı​

Uygulamamız şu temel bileşenlerden oluşacak:
  • UI: Notların listelendiği bir ana ekran ve not ekleme/düzenleme ekranı.
  • Veritabanı: Room ile SQLite tabanlı yerel bir veritabanı.
  • ViewModel: UI ile veri arasındaki iletişimi yönetmek için.

Bağımlılıkları Ekleme​

build.gradle.kts (app) dosyasına aşağıdaki bağımlılıkları ekleyin:

Kod:
dependencies {
    implementation("androidx.room:room-runtime:2.6.1")
    kapt("androidx.room:room-compiler:2.6.1")
    implementation("androidx.room:room-ktx:2.6.1")
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0")
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.0")
    implementation("androidx.recyclerview:recyclerview:1.3.2")
}

plugins bloğuna kapt eklentisini ekleyin:

Kod:
plugins {
    id("kotlin-kapt")
}

Değişiklikleri yaptıktan sonra projeyi senkronize edin.

Adım 1: Veritabanı Kurulumu​

Room ile notları saklamak için bir veritabanı oluşturacağız. Notlar, başlık ve içerik alanlarına sahip olacak.

Entity (Not Modeli)​

data paketinde Note.kt dosyasını oluşturun:

Kod:
package com.example.noteapp.data

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "notes")
data class Note(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    val title: String,
    val content: String
)

DAO (Veri Erişim Nesnesi)​

data paketinde NoteDao.kt dosyasını oluşturun:

Kod:
package com.example.noteapp.data

import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import kotlinx.coroutines.flow.Flow

@Dao
interface NoteDao {
    @Query("SELECT * FROM notes")
    fun getAllNotes(): Flow<List<Note>>

    @Insert
    suspend fun insert(note: Note)

    @Update
    suspend fun update(note: Note)

    @Delete
    suspend fun delete(note: Note)
}

Veritabanı Sınıfı​

data paketinde NoteDatabase.kt dosyasını oluşturun:

Kod:
package com.example.noteapp.data

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(entities = [Note::class], version = 1, exportSchema = false)
abstract class NoteDatabase : RoomDatabase() {
    abstract fun noteDao(): NoteDao

    companion object {
        @Volatile
        private var INSTANCE: NoteDatabase? = null

        fun getDatabase(context: Context): NoteDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    NoteDatabase::class.java,
                    "note_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

Adım 2: ViewModel Oluşturma​

viewmodel paketinde NoteViewModel.kt dosyasını oluşturun:

Kod:
package com.example.noteapp.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.noteapp.data.Note
import com.example.noteapp.data.NoteDao
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch

class NoteViewModel(private val noteDao: NoteDao) : ViewModel() {

    val allNotes: Flow<List<Note>> = noteDao.getAllNotes()

    fun insert(note: Note) {
        viewModelScope.launch {
            noteDao.insert(note)
        }
    }

    fun update(note: Note) {
        viewModelScope.launch {
            noteDao.update(note)
        }
    }

    fun delete(note: Note) {
        viewModelScope.launch {
            noteDao.delete(note)
        }
    }
}

Adım 3: Kullanıcı Arayüzü (UI)​

Ana Ekran (Not Listesi)​

res/layout/activity_main.xml dosyasını güncelleyin:

Kod:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/addButton"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/addButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/ic_input_add"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Not Ekleme/Düzenleme Ekranı​

res/layout/activity_add_edit_note.xml dosyasını oluşturun:

Kod:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <EditText
        android:id="@+id/titleEditText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="Not Başlığı"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/contentEditText"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:hint="Not İçeriği"
        android:gravity="top"
        android:inputType="textMultiLine"
        app:layout_constraintBottom_toTopOf="@id/saveButton"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/titleEditText" />

    <Button
        android:id="@+id/saveButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Kaydet"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

RecyclerView için Öğe Düzeni​

res/layout/item_note.xml dosyasını oluşturun:

Kod:
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="16dp">

        <TextView
            android:id="@+id/titleTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/contentTextView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="14sp" />

    </LinearLayout>
</androidx.cardview.widget.CardView>

Adım 4: Kodlama​

RecyclerView Adaptörü​

adapter paketinde NoteAdapter.kt dosyasını oluşturun:

Kod:
package com.example.noteapp.adapter

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.noteapp.data.Note
import com.example.noteapp.databinding.ItemNoteBinding

class NoteAdapter(
    private val notes: List<Note>,
    private val onClick: (Note) -> Unit
) : RecyclerView.Adapter<NoteAdapter.NoteViewHolder>() {

    class NoteViewHolder(private val binding: ItemNoteBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(note: Note, onClick: (Note) -> Unit) {
            binding.titleTextView.text = note.title
            binding.contentTextView.text = note.content
            binding.root.setOnClickListener { onClick(note) }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteViewHolder {
        val binding = ItemNoteBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return NoteViewHolder(binding)
    }

    override fun onBindViewHolder(holder: NoteViewHolder, position: Int) {
        holder.bind(notes[position], onClick)
    }

    override fun getItemCount(): Int = notes.size
}

Ana Aktivite​

MainActivity.kt dosyasını güncelleyin:

Kod:
package com.example.noteapp

import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.noteapp.adapter.NoteAdapter
import com.example.noteapp.data.NoteDatabase
import com.example.noteapp.databinding.ActivityMainBinding
import com.example.noteapp.viewmodel.NoteViewModel
import kotlinx.coroutines.flow.collectLatest

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val viewModel: NoteViewModel by viewModels {
        NoteViewModelFactory(NoteDatabase.getDatabase(this).noteDao())
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.recyclerView.layoutManager = LinearLayoutManager(this)

        lifecycleScope.launchWhenStarted {
            viewModel.allNotes.collectLatest { notes ->
                binding.recyclerView.adapter = NoteAdapter(notes) { note ->
                    val intent = Intent(this@MainActivity, AddEditNoteActivity::class.java)
                    intent.putExtra("noteId", note.id)
                    startActivity(intent)
                }
            }
        }

        binding.addButton.setOnClickListener {
            startActivity(Intent(this, AddEditNoteActivity::class.java))
        }
    }
}

Not Ekleme/Düzenleme Aktivitesi​

AddEditNoteActivity.kt dosyasını oluşturun:

Kod:
package com.example.noteapp

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import com.example.noteapp.data.Note
import com.example.noteapp.data.NoteDatabase
import com.example.noteapp.databinding.ActivityAddEditNoteBinding
import com.example.noteapp.viewmodel.NoteViewModel
import com.example.noteapp.viewmodel.NoteViewModelFactory

class AddEditNoteActivity : AppCompatActivity() {

    private lateinit var binding: ActivityAddEditNoteBinding
    private val viewModel: NoteViewModel by viewModels {
        NoteViewModelFactory(NoteDatabase.getDatabase(this).noteDao())
    }
    private var noteId: Int? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityAddEditNoteBinding.inflate(layoutInflater)
        setContentView(binding.root)

        noteId = intent.getIntExtra("noteId", -1).takeIf { it != -1 }

        noteId?.let { id ->
            viewModel.allNotes.observe(this) { notes ->
                val note = notes.find { it.id == id }
                note?.let {
                    binding.titleEditText.setText(it.title)
                    binding.contentEditText.setText(it.content)
                }
            }
        }

        binding.saveButton.setOnClickListener {
            val title = binding.titleEditText.text.toString()
            val content = binding.contentEditText.text.toString()

            if (title.isNotBlank()) {
                val note = Note(
                    id = noteId ?: 0,
                    title = title,
                    content = content
                )
                if (noteId == null) {
                    viewModel.insert(note)
                } else {
                    viewModel.update(note)
                }
                finish()
            }
        }
    }
}

ViewModel Factory​

viewmodel paketinde NoteViewModelFactory.kt dosyasını oluşturun:

Kod:
package com.example.noteapp.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.noteapp.data.NoteDao

class NoteViewModelFactory(private val noteDao: NoteDao) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(NoteViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return NoteViewModel(noteDao) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

Adım 5: Uygulamayı Test Etme​

  1. Android Studio’da emülatörü başlatın veya fiziksel bir cihaz bağlayın.
  2. Projeyi derleyin ve çalıştırın.
  3. Uygulamada:
    • Yeni not eklemek için “+” düğmesine tıklayın.
    • Notları listelemek için ana ekrana dönün.
    • Bir nota tıklayarak düzenleyin veya yeni içerik ekleyin.

FAQS​

S: Uygulama verileri cihazda nasıl saklıyor?
C: Uygulama, Room kütüphanesi ile SQLite veritabanını kullanıyor. Veriler cihazda yerel olarak saklanıyor.

S: Notları silme özelliği nasıl eklenir?
C: Notları silmek için NoteAdapter’da uzun tıklama (long press) işlevi ekleyebilir ve NoteViewModel üzerinden delete metodunu çağırabilirsiniz.

S: Uygulamayı nasıl geliştirebilirim?
C: Şu özellikler eklenebilir:
  • Kategorilere göre not ayırma.
  • Notlara tarih/zaman damgası ekleme.
  • Bulut senkronizasyonu (örneğin, Firebase ile).
S: Room yerine başka bir veritabanı kullanabilir miyim?
C: Evet, örneğin SharedPreferences veya SQLite doğrudan kullanılabilir, ancak Room daha modern ve Kotlin dostu bir çözümdür.

Sonuç​

Bu rehberde, Kotlin ile basit bir not alma uygulamasının nasıl geliştirileceğini adım adım öğrendik. Room, ViewModel ve RecyclerView gibi modern Android geliştirme araçlarını kullanarak hem performanslı hem de kullanıcı dostu bir uygulama oluşturduk. Bu projeyi temel alarak daha fazla özellik ekleyebilir ve kendi ihtiyaçlarınıza göre özelleştirebilirsiniz.
 
Üst