Skip to content

Commit

Permalink
更新备份恢复数据库的实现方式
Browse files Browse the repository at this point in the history
不再支持旧方式
使用 Room Backup 1.0.2,对其部分代码改用 Kotlin 原生实现,部分参考 LibChecker 的实现
  • Loading branch information
Super12138 committed Dec 25, 2024
1 parent cb33415 commit 77fc592
Show file tree
Hide file tree
Showing 14 changed files with 1,260 additions and 190 deletions.
6 changes: 3 additions & 3 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,16 @@ dependencies {
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.preference)
implementation(libs.androidx.preference.ktx)
implementation(libs.androidx.security)
// Material Design
implementation(libs.material)
// Room
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
annotationProcessor(libs.androidx.room.compiler)
ksp(libs.androidx.room.compiler)
// Gson
implementation(libs.gson)
// Room Backup
// implementation(libs.room.backup)
// Fast Scroll
implementation(libs.fast.scroll)
// Test
Expand All @@ -100,7 +101,6 @@ dependencies {

fun String.exec(): String = exec(this)

@Suppress("UnstableApiUsage")
fun Project.exec(command: String): String = providers.exec {
commandLine(command.split(" "))
}.standardOutput.asText.get().trim()
11 changes: 2 additions & 9 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,5 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

# Gson
-keepattributes Signature
-keep class com.google.gson.reflect.TypeToken { *; }
-keep class * extends com.google.gson.reflect.TypeToken
-keepattributes AnnotationDefault,RuntimeVisibleAnnotations

# ToDo Room
-keep class cn.super12138.todo.logic.dao.ToDoRoom { *; }
-dontwarn javax.annotation.Nullable
-dontwarn javax.annotation.concurrent.GuardedBy
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</activity>
<activity
android:name=".views.activities.CrashActivity"
android:exported="false" />
android:exported="false"
android:theme="@style/Theme.ToDo" />
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ import cn.super12138.todo.databinding.ActivityMainBinding
import cn.super12138.todo.views.BaseActivity
import cn.super12138.todo.views.fragments.SettingsParentFragment
import cn.super12138.todo.views.fragments.welcome.WelcomeFragment
import de.raphaelebner.roomdatabasebackup.core.RoomBackup

class MainActivity : BaseActivity<ActivityMainBinding>() {
lateinit var roomBackup: RoomBackup
override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
Expand All @@ -32,6 +34,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
false -> window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
}
handleIntent(intent)

roomBackup = RoomBackup(this)
}

override fun onNewIntent(intent: Intent, caller: ComponentCaller) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,30 @@ import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat
import cn.super12138.todo.R
import cn.super12138.todo.constant.Constants
import cn.super12138.todo.constant.GlobalValues
import cn.super12138.todo.databinding.DialogBackupBinding
import cn.super12138.todo.databinding.DialogRestoreBinding
import cn.super12138.todo.logic.Repository
import cn.super12138.todo.logic.dao.ToDoRoom
import cn.super12138.todo.logic.dao.ToDoRoomDB
import cn.super12138.todo.utils.VibrationUtils
import cn.super12138.todo.views.activities.MainActivity
import cn.super12138.todo.views.fragments.welcome.WelcomeFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.launch
import de.raphaelebner.roomdatabasebackup.core.RoomBackup
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import kotlin.system.exitProcess

class SettingsFragment : PreferenceFragmentCompat() {
private lateinit var backupBinding: DialogBackupBinding
private lateinit var restoreBinding: DialogRestoreBinding

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
val mainActivity = requireActivity() as MainActivity
val gson = Gson()
val roomBackup = mainActivity.roomBackup

findPreference<ListPreference>(Constants.PREF_DARK_MODE)?.apply {
setOnPreferenceClickListener {
Expand Down Expand Up @@ -87,22 +78,35 @@ class SettingsFragment : PreferenceFragmentCompat() {
findPreference<Preference>(Constants.PREF_BACKUP_DB)?.apply {
setOnPreferenceClickListener {
VibrationUtils.performHapticFeedback(view)
lifecycleScope.launch {
val data = Repository.getAll()
val jsonData = gson.toJson(data)
backupBinding = DialogBackupBinding.inflate(layoutInflater)
backupBinding.jsonOutput.text = jsonData

activity?.let {
MaterialAlertDialogBuilder(it)
.setTitle(R.string.export_data)
.setView(backupBinding.root)
.setPositiveButton(R.string.ok) { _, _ ->
VibrationUtils.performHapticFeedback(view)
val simpleDateFormat =
SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
val formattedDate = simpleDateFormat.format(Date())
roomBackup
.database(ToDoRoomDB.getDatabase(requireContext()))
.enableLogDebug(GlobalValues.devMode)
.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_DIALOG)
.customBackupFileName("ToDo-DataBase-$formattedDate.sqlite3")
.apply {
onCompleteListener { success, _, exitCode ->
if (success) {
view?.let { it1 ->
Snackbar.make(
it1, R.string.tips_backup_success, Snackbar.LENGTH_LONG
).show()
}
} else {
view?.let { it1 ->
Snackbar.make(
it1, getString(
R.string.tips_backup_failed,
exitCode
), Snackbar.LENGTH_LONG
).show()
}
}
.show()
}
}
}
.backup()
true
}
}
Expand All @@ -111,61 +115,39 @@ class SettingsFragment : PreferenceFragmentCompat() {
setOnPreferenceClickListener {
VibrationUtils.performHapticFeedback(view)

roomBackup
.database(ToDoRoomDB.getDatabase(requireContext()))
.enableLogDebug(GlobalValues.devMode)
.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_DIALOG)
.apply {
onCompleteListener { success, _, exitCode ->
if (success) {
view?.let { it1 ->
Snackbar.make(
it1,
R.string.tips_restore_success,
Snackbar.LENGTH_LONG
)
.setAction(R.string.restart_app_now) {
VibrationUtils.performHapticFeedback(view)
restartApp(context)
}
.show()
}

restoreBinding = DialogRestoreBinding.inflate(layoutInflater)
activity?.let { it1 ->
val dialog = MaterialAlertDialogBuilder(it1)
.setTitle(R.string.restore_data)
.setView(restoreBinding.root)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, null)
.show()

dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
VibrationUtils.performHapticFeedback(view)

val jsonInput = restoreBinding.jsonInput.editText?.text.toString()
if (jsonInput.isEmpty()) {
restoreBinding.jsonInput.error =
getString(R.string.please_paste_data)
return@setOnClickListener
}

lifecycleScope.launch {
if (restoreBinding.overwriteData.isChecked) {
Repository.deleteAll()
}
try {
val listType = object : TypeToken<List<ToDoRoom>>() {}.type
val taskList: List<ToDoRoom> =
gson.fromJson(jsonInput, listType)
taskList.forEach { Repository.insert(it) }
dialog.dismiss()
MaterialAlertDialogBuilder(it1)
.setTitle(R.string.restore_successful)
.setMessage(R.string.restore_need_restart_app)
.setPositiveButton(R.string.ok) { _, _ ->
VibrationUtils.performHapticFeedback(view)

restartApp(context)
}
.setNegativeButton(R.string.cancel, null)
.setCancelable(false)
.show()
} catch (e: JsonSyntaxException) {
restoreBinding.jsonInput.error =
getString(R.string.json_data_incorrect)
} catch (e: Exception) {
if (GlobalValues.devMode) {
restoreBinding.jsonInput.error = e.toString()
} else {
restoreBinding.jsonInput.error =
getString(R.string.restore_failed)
} else {
view?.let { it1 ->
Snackbar.make(
it1, getString(
R.string.tips_restore_failed,
exitCode
), Snackbar.LENGTH_LONG
).show()
}
}
}
}
}
.restore()
true
}
}
Expand Down Expand Up @@ -195,7 +177,6 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}


override fun setDivider(divider: Drawable?) {
super.setDivider(ColorDrawable(Color.TRANSPARENT))
}
Expand All @@ -204,7 +185,6 @@ class SettingsFragment : PreferenceFragmentCompat() {
super.setDividerHeight(0)
}


private fun restartApp(restartContext: Context) {
val intent = Intent(restartContext, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
Expand Down
Loading

0 comments on commit 77fc592

Please sign in to comment.