29 Multi-Threading in Android

Multi-Threading in Android ist entscheidend, um die Benutzeroberfläche (UI) reaktionsfähig zu halten. Der Hauptthread (UI-Thread) ist für UI-Interaktionen und -Aktualisierungen zuständig. Lange laufende Operationen, wie Netzwerkanfragen oder Datenbanktransaktionen, sollten daher auf Hintergrundthreads ausgeführt werden, um den UI-Thread nicht zu blockieren.

29.1 Wichtige Konzepte und Techniken

29.1.1 Handler und Looper

29.1.2 AsyncTask (Veraltet seit API 30)

29.1.3 Java Threads und Runnables

29.1.4 Coroutines in Kotlin

29.1.5 WorkManager

29.2 Beispiel: Nutzung von Coroutines

Coroutines in Kotlin sind eine leistungsstarke Lösung für asynchrone Programmierung, die das Schreiben von sauberem und einfachem Code ermöglicht:

GlobalScope.launch(Dispatchers.IO) {
    // Lange laufende Operation; Netzwerkanfrage, Datenbankabfrage, etc.
    val data = fetchData()

    withContext(Dispatchers.Main) {
        // Aktualisiere die UI mit den abgerufenen Daten
        updateUI(data)
    }
}

In diesem Beispiel wird fetchData() auf einem Hintergrundthread ausgeführt, während updateUI(data) sicher auf dem Hauptthread ausgeführt wird, um die UI zu aktualisieren.

29.3 Wichtige Hinweise

Die korrekte Anwendung von Multi-Threading in Android-Apps ist entscheidend für eine reaktionsfähige Benutzererfahrung und die Systemstabilität.

Verstanden, hier ist die Anpassung für die Arbeit mit Datenbanken in Android, komplett in Kotlin formuliert:

29.4 SQLite-Datenbank

SQLite ist eine eingebettete SQL-Datenbank, die leichte Transaktionen unterstützt. Sie ist direkt in Android integriert und ideal für die Speicherung und Abfrage strukturierter Daten.

29.4.1 Direkte Nutzung der SQLite-API in Kotlin

Die direkte Arbeit mit SQLite in Kotlin kann über die Klasse SQLiteOpenHelper und zugehörige Schnittstellen erfolgen. Hier ist ein Beispiel, wie man eine SQLite-Datenbank in Kotlin erstellt und nutzt:

class DatabaseHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
    override fun onCreate(db: SQLiteDatabase) {
        db.execSQL("CREATE TABLE $TABLE_NAME (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, MARKS INTEGER)")
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
        db.execSQL("DROP TABLE IF EXISTS $TABLE_NAME")
        onCreate(db)
    }

    fun getAllData(): Cursor {
        val db = this.writableDatabase
        return db.rawQuery("SELECT * FROM $TABLE_NAME", null)
    }

    companion object {
        const val DATABASE_NAME = "Student.db"
        const val TABLE_NAME = "student_table"
    }
}

29.4.2 Room-Persistence-Bibliothek

Room bietet eine abstrakte Schicht über SQLite, um die Datenbankinteraktion flüssiger und sicherer zu gestalten. Definieren Sie Entitäten, DAOs und Datenbanken wie folgt:

@Entity
data class User(
    @PrimaryKey val id: Int,
    val name: String,
    val age: Int
)

@Dao
interface UserDao {
    @Query("SELECT * FROM User")
    fun getAllUsers(): List<User>

    @Insert
    fun insertAll(vararg users: User)

    @Delete
    fun deleteUser(user: User)
}

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

29.4.3 Asynchrone Datenbankoperationen mit Coroutines

Um Datenbankoperationen ohne Blockierung des UI-Threads durchzuführen, nutzen Sie Kotlin Coroutines zusammen mit Room:

val db = Room.databaseBuilder(
    applicationContext,
    AppDatabase::class.java, "database-name"
).build()

GlobalScope.launch {
    val users = db.userDao().getAllUsers()
    // Verarbeiten Sie die abgerufenen Benutzerdaten
}

29.4.4 Best Practices

Mit der Room-Persistence-Bibliothek und Kotlin Coroutines bietet Android ein starkes Set von Tools zur effizienten und effektiven Verwaltung von Datenbankoperationen.