Erkag
Administrator
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.
- Empty Activity şablonunu seçin.
- Dil olarak Kotlin’i seçin.
- 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
- Android Studio’da emülatörü başlatın veya fiziksel bir cihaz bağlayın.
- Projeyi derleyin ve çalıştırın.
- 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).
C: Evet, örneğin SharedPreferences veya SQLite doğrudan kullanılabilir, ancak Room daha modern ve Kotlin dostu bir çözümdür.