Big commit.
Managed to do upload and download right. No Race conditions.
This commit is contained in:
@ -11,7 +11,8 @@ import androidx.room.RoomDatabase
|
|||||||
Answer::class,
|
Answer::class,
|
||||||
CompletedQuestionnaire::class
|
CompletedQuestionnaire::class
|
||||||
],
|
],
|
||||||
version = 10
|
version = 1,
|
||||||
|
exportSchema = false
|
||||||
)
|
)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
abstract fun clientDao(): ClientDao
|
abstract fun clientDao(): ClientDao
|
||||||
@ -20,3 +21,4 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
abstract fun answerDao(): AnswerDao
|
abstract fun answerDao(): AnswerDao
|
||||||
abstract fun completedQuestionnaireDao(): CompletedQuestionnaireDao
|
abstract fun completedQuestionnaireDao(): CompletedQuestionnaireDao
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,8 +12,15 @@ interface ClientDao {
|
|||||||
|
|
||||||
@Delete
|
@Delete
|
||||||
suspend fun deleteClient(client: Client)
|
suspend fun deleteClient(client: Client)
|
||||||
|
|
||||||
|
@Query("SELECT COUNT(*) FROM clients")
|
||||||
|
suspend fun getClientCount(): Int
|
||||||
|
|
||||||
|
@Query("SELECT * FROM clients")
|
||||||
|
suspend fun getAllClients(): List<Client>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface QuestionnaireDao {
|
interface QuestionnaireDao {
|
||||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
|
|||||||
@ -18,7 +18,8 @@ import kotlin.system.exitProcess
|
|||||||
object DatabaseUploader {
|
object DatabaseUploader {
|
||||||
|
|
||||||
private const val DB_NAME = "questionnaire_database"
|
private const val DB_NAME = "questionnaire_database"
|
||||||
private const val SERVER_DELTA_URL = "http://49.13.157.44/uploadDelta.php"
|
// TODO entferne uploadDeltaTest.php
|
||||||
|
private const val SERVER_DELTA_URL = "http://49.13.157.44/uploadDeltaTest.php"
|
||||||
private const val SERVER_CHECK_URL = "http://49.13.157.44/checkDatabaseExists.php"
|
private const val SERVER_CHECK_URL = "http://49.13.157.44/checkDatabaseExists.php"
|
||||||
private const val API_TOKEN = "MEIN_SUPER_GEHEIMES_TOKEN_12345"
|
private const val API_TOKEN = "MEIN_SUPER_GEHEIMES_TOKEN_12345"
|
||||||
|
|
||||||
@ -56,10 +57,10 @@ object DatabaseUploader {
|
|||||||
val exists = checkDatabaseExists()
|
val exists = checkDatabaseExists()
|
||||||
if (exists) {
|
if (exists) {
|
||||||
Log.d("UPLOAD", "Server-Datenbank vorhanden → Delta-Upload")
|
Log.d("UPLOAD", "Server-Datenbank vorhanden → Delta-Upload")
|
||||||
uploadDelta(dbFile)
|
uploadPseudoDelta(dbFile)
|
||||||
} else {
|
} else {
|
||||||
Log.d("UPLOAD", "Keine Server-Datenbank → Delta-Upload")
|
Log.d("UPLOAD", "Keine Server-Datenbank → Delta-Upload")
|
||||||
uploadDelta(dbFile)
|
uploadPseudoDelta(dbFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -94,7 +95,7 @@ object DatabaseUploader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun uploadDelta(file: File) {
|
private fun uploadPseudoDelta(file: File) {
|
||||||
try {
|
try {
|
||||||
val db = SQLiteDatabase.openDatabase(file.absolutePath, null, SQLiteDatabase.OPEN_READONLY)
|
val db = SQLiteDatabase.openDatabase(file.absolutePath, null, SQLiteDatabase.OPEN_READONLY)
|
||||||
|
|
||||||
@ -138,12 +139,18 @@ object DatabaseUploader {
|
|||||||
}
|
}
|
||||||
if (response.isSuccessful) {
|
if (response.isSuccessful) {
|
||||||
Log.d("UPLOAD", "Delta-Upload erfolgreich: $body")
|
Log.d("UPLOAD", "Delta-Upload erfolgreich: $body")
|
||||||
|
// Lösche Hauptdatenbank
|
||||||
if (file.delete()) {
|
if (file.delete()) {
|
||||||
Log.d("UPLOAD", "Lokale DB gelöscht.")
|
Log.d("UPLOAD", "Lokale DB gelöscht.")
|
||||||
exitProcess(0)
|
|
||||||
} else {
|
} else {
|
||||||
Log.e("UPLOAD", "Löschen der lokalen DB fehlgeschlagen.")
|
Log.e("UPLOAD", "Löschen der lokalen DB fehlgeschlagen.")
|
||||||
}
|
}
|
||||||
|
// Lösche Journal-Datei
|
||||||
|
val journalFile = File(file.parent, file.name + "-journal")
|
||||||
|
if (journalFile.exists() && journalFile.delete()) {
|
||||||
|
Log.d("UPLOAD", "Journal-Datei gelöscht.")
|
||||||
|
}
|
||||||
|
exitProcess(0)
|
||||||
} else {
|
} else {
|
||||||
Log.e("UPLOAD", "Delta-Upload fehlgeschlagen: ${response.code} $body")
|
Log.e("UPLOAD", "Delta-Upload fehlgeschlagen: ${response.code} $body")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import android.widget.*
|
|||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
var INTEGRATION_INDEX_POINTS: Int? = null
|
var INTEGRATION_INDEX_POINTS: Int? = null
|
||||||
@ -35,6 +36,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
|||||||
activity.setContentView(R.layout.opening_screen)
|
activity.setContentView(R.layout.opening_screen)
|
||||||
|
|
||||||
bindViews()
|
bindViews()
|
||||||
|
|
||||||
loadQuestionnaireOrder()
|
loadQuestionnaireOrder()
|
||||||
createQuestionnaireButtons()
|
createQuestionnaireButtons()
|
||||||
restorePreviousClientCode()
|
restorePreviousClientCode()
|
||||||
@ -46,11 +48,22 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
|||||||
setupUploadButton()
|
setupUploadButton()
|
||||||
setupDownloadButton()
|
setupDownloadButton()
|
||||||
|
|
||||||
|
val dbPath = "/data/data/com.dano.test1/databases/questionnaire_database"
|
||||||
|
val pathExists = File(dbPath).exists()
|
||||||
|
if (pathExists) {
|
||||||
|
updateMainButtonsState(true)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
updateMainButtonsState(false)
|
||||||
|
}
|
||||||
|
|
||||||
if (!editText.text.isNullOrBlank()) {
|
if (!editText.text.isNullOrBlank()) {
|
||||||
buttonLoad.performClick()
|
buttonLoad.performClick()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun bindViews() {
|
private fun bindViews() {
|
||||||
editText = activity.findViewById(R.id.editText)
|
editText = activity.findViewById(R.id.editText)
|
||||||
spinner = activity.findViewById(R.id.string_spinner1)
|
spinner = activity.findViewById(R.id.string_spinner1)
|
||||||
@ -183,13 +196,12 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
updateMainButtonsState(true) // Datenbank vorhanden -> Buttons aktivieren
|
||||||
handleNormalLoad(clientCode)
|
handleNormalLoad(clientCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private suspend fun handleNormalLoad(clientCode: String) {
|
private suspend fun handleNormalLoad(clientCode: String) {
|
||||||
val completedIds = withContext(Dispatchers.IO) {
|
val completedIds = withContext(Dispatchers.IO) {
|
||||||
MyApp.database.completedQuestionnaireDao().getCompletedQuestionnairesForClient(clientCode)
|
MyApp.database.completedQuestionnaireDao().getCompletedQuestionnairesForClient(clientCode)
|
||||||
@ -559,6 +571,22 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Füge diese Funktion in deine Klasse ein ---
|
||||||
|
private fun isDatabasePopulated(): Boolean {
|
||||||
|
return try {
|
||||||
|
// Wir prüfen, ob die Datenbank mindestens eine nicht-interne Tabelle enthält.
|
||||||
|
// Das ist robust gegenüber verschiedenen Tabellennamen.
|
||||||
|
val db = MyApp.database.openHelper.readableDatabase
|
||||||
|
val cursor = db.query(
|
||||||
|
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != 'room_master_table'"
|
||||||
|
)
|
||||||
|
cursor.use { it.count > 0 }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
// Falls etwas schiefgeht (z.B. DB noch nicht vorhanden), gilt: nicht vorhanden
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setupDownloadButton() {
|
private fun setupDownloadButton() {
|
||||||
downloadButton.text = "Download"
|
downloadButton.text = "Download"
|
||||||
downloadButton.setOnClickListener {
|
downloadButton.setOnClickListener {
|
||||||
@ -568,7 +596,15 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
|
|||||||
|
|
||||||
Toast.makeText(activity, "Datenbank wird heruntergeladen...", Toast.LENGTH_SHORT).show()
|
Toast.makeText(activity, "Datenbank wird heruntergeladen...", Toast.LENGTH_SHORT).show()
|
||||||
DatabaseDownloader.downloadAndReplaceDatabase(activity)
|
DatabaseDownloader.downloadAndReplaceDatabase(activity)
|
||||||
|
updateMainButtonsState(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateMainButtonsState(isDatabaseAvailable: Boolean) {
|
||||||
|
val buttons = listOf(buttonLoad, saveButton, editButton)
|
||||||
|
buttons.forEach { button ->
|
||||||
|
button.isEnabled = isDatabaseAvailable
|
||||||
|
button.alpha = if (isDatabaseAvailable) 1.0f else 0.5f
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
package com.dano.test1
|
package com.dano.test1
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.util.Log
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
|
import androidx.room.RoomDatabase
|
||||||
import com.dano.test1.data.AppDatabase
|
import com.dano.test1.data.AppDatabase
|
||||||
|
|
||||||
class MyApp : Application() {
|
class MyApp : Application() {
|
||||||
@ -13,12 +15,21 @@ class MyApp : Application() {
|
|||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
|
// Room Datenbank bauen: nur die Hauptdatei, ohne WAL und Journal
|
||||||
database = Room.databaseBuilder(
|
database = Room.databaseBuilder(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
AppDatabase::class.java,
|
AppDatabase::class.java,
|
||||||
"questionnaire_database"
|
"questionnaire_database"
|
||||||
)
|
)
|
||||||
.fallbackToDestructiveMigration()
|
.fallbackToDestructiveMigration()
|
||||||
|
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE) // TRUNCATE = keine -wal Datei, nur Hauptdatei
|
||||||
|
.addCallback(object : RoomDatabase.Callback() {
|
||||||
|
override fun onOpen(db: androidx.sqlite.db.SupportSQLiteDatabase) {
|
||||||
|
super.onOpen(db)
|
||||||
|
Log.d("DB", "Datenbank geöffnet. Nur questionnaire_database wird genutzt.")
|
||||||
|
}
|
||||||
|
})
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user