当前位置:网站首页>Backup and restore of Android local SQLite database
Backup and restore of Android local SQLite database
2022-07-05 13:13:00 【Vaccae】
Learn better people ,
Be a better person .
——《 Smart enjoyment of wechat 》
The length of this paper is 3024 word , Expected reading 6 minute
Preface
Internet Android APP In fact, a lot of development is Android End writing UI, Business logic passed API Callback display data , And I mainly deal with hardware equipment , At ordinary times, we should also consider the normal use of a single machine when the network is not available , So all business logic is implemented in the program , Data localization requirements are also high , It needs to be used Sqlite database , So this article is devoted to Sqlite Database backup and restore .
How to achieve Sqlite Database backup and restore ?
A
Actually realize Sqlite The backup and restore principle of is still relatively simple , Will be App Generated in the Sqlite Copy the database file of to the storage area , Restore is to copy the copied database files back to the database directory specified by the program . But here is a key problem , The storage directory must be the external directory specified by yourself , If you are backing up the database file or the directory under the package , The installation upgrade signature is incorrect , Or manually open the application and click clear data , The local database and backup database files will also be emptied , The consequences can be imagined ....
Realization effect
1. Three local database files
2.SD There is no backup file in the card directory
3. Click backup database
4.SD The database has been copied from the card directory
5. Delete the original databases Directory database
6. After re inquiry, nothing is displayed
7. Click restore database databases The files in the directory have been copied back
8. Click again to query data , You can see the displayed data
Core code
Smart enjoyment of wechat
Backup and restore classes (DbBackupUtil)
package com.vaccae.roomdemo
import android.annotation.SuppressLint
import android.content.Context
import android.os.Environment
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
/**
* author :Vaccae
* mailbox :[email protected]
* Creation time :18:22
* Function module description :
*/
class DbBackupUtil {
private var mContext: Context? = null
val path =
Environment.getExternalStorageDirectory().absolutePath + File.separator + "RoomBackup" + File.separator
private fun getInstance(context: Context) {
mContext ?: run {
synchronized(DbBackupUtil::class.java) {
mContext = context
}
}
}
private fun createPath() {
// Installation package path
val updateDir = File(path)
// Create folder
if (!updateDir.exists()) {
updateDir.mkdirs()
}
}
suspend fun backup(context: Context): Flow<String> = flow {
getInstance(context)
createPath()
mContext?.let {
val strs = it.databaseList()
emit(" common ${strs.size} A database file , Start backup ")
for (str in strs) {
emit(" Backup now ${str} database ...")
// Find the path to the file /data/data/ Package name /databases/ Database name
val dbFile = it.getDatabasePath(str)
//val dstFile = it.getExternalFilesDir("db").toString() + "/" + str
val dstFile = path + str;
var fis: FileInputStream? = null
var fos: FileOutputStream? = null
try {
// File copy to sd In the card
fis = FileInputStream(dbFile)
fos = FileOutputStream(dstFile)
var len = 0
val buffer = ByteArray(2048)
while (-1 != fis.read(buffer).also({ len = it })) {
fos.write(buffer, 0, len)
}
fos.flush()
emit("${str} Database backup complete ...")
} catch (e: Exception) {
throw e
} finally {
// Turn off data flow
try {
fos?.close()
fis?.close()
} catch (e: IOException) {
throw e
}
}
}
emit(" All database backups are complete ")
} ?: kotlin.run { throw Exception(" Undefined Context") }
}
suspend fun restore(context: Context): Flow<String> {
return flow {
getInstance(context)
createPath()
mContext?.let {
//var dbfiles = it.getExternalFilesDir("db")
var dbfiles = File(path)
dbfiles.let { dbs ->
var files = dbs.listFiles()
if (files.isNotEmpty()) {
emit(" common ${files.size} A database file , Start restoring ")
for (str in files) {
var dbFile = it.getDatabasePath(str.name)
dbFile.delete()
var fis: FileInputStream? = null
var fos: FileOutputStream? = null
try {
// File copy to sd In the card
fis = FileInputStream(str)
fos = FileOutputStream(dbFile)
var len = 0
val buffer = ByteArray(2048)
while (-1 != fis.read(buffer).also({ len = it })) {
fos.write(buffer, 0, len)
}
fos.flush()
emit("${str} Database restore completed ...")
} catch (e: Exception) {
throw e
} finally {
// Turn off data flow
try {
fos?.close()
fis?.close()
} catch (e: IOException) {
throw e
}
}
}
emit(" All databases are restored ")
}
}
} ?: kotlin.run { throw Exception(" Undefined Context") }
}
}
}
Activity In the call
// Backup call
btnbackup.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
DbBackupUtil().backup(applicationContext)
.flowOn(Dispatchers.IO)
.collect(collector = FlowCollector { t ->
tvshow.text = t
})
}
}
// Restore call
btnrestore.setOnClickListener {
GlobalScope.launch(Dispatchers.Main) {
DbBackupUtil().restore(applicationContext)
.flowOn(Dispatchers.IO)
.collect(collector = FlowCollector { t ->
tvshow.text = t
})
}
}
Smart enjoyment of wechat
Key points
1. Backup and restore adopt return flow In the form of , Because there are three databases , This can be done in UI The interface shows the restore progress .
Send current progress
UI Show current progress
2. The backed up database files are stored in SD Card custom directory , Prevent the application from clicking to clear data , If the backup file is also copied to the package directory, it will also be deleted . However, for storage permissions , stay Android 6.0 Then it becomes dangerous authority , And by the Android 11 It becomes a special permission , You must authorize all file management permissions .
AndroidManifest Add list permissions to
There is also the directory of storage
Corresponding xml/file_pahts.xml In the definition of external-path
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.vaccae.roomdemo">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:exported="true"
android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>
file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The final setting inside NAME and PATH It should be the same as the name of the folder , The corresponding file will be found -->
<external-path name="RoomBackup" path="RoomBackup"/>
</paths>
Activity Dynamically apply for permission in
StartActivityforResult It's abandoned , So use registerForActivityResult To achieve
Apply for permission function
MainActivity Application permission code
class MainActivity : AppCompatActivity() {
companion object {
private const val REQUEST_CODE_PERMISSIONS = 10
private val REQUIRED_PERMISSIONS = arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.CHANGE_NETWORK_STATE,
Manifest.permission.INTERNET
)
}
//StartActivity After abandonment , Use registerForActivityResult To achieve
private val requestDataLauncher =
registerForActivityResult(object : ActivityResultContract<Int, String>() {
override fun createIntent(context: Context, input: Int?): Intent {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.data = Uri.parse("package:$packageName")
return intent
}
override fun parseResult(resultCode: Int, intent: Intent?): String {
TODO("Not yet implemented")
}
}
) {
Toast.makeText(this, it, Toast.LENGTH_SHORT).show()
}
private fun allPermissionsGranted() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// First judge whether you have permission
if (Environment.isExternalStorageManager()) {
REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
baseContext,
it
) == PackageManager.PERMISSION_GRANTED
}
} else {
requestDataLauncher.launch(REQUEST_CODE_PERMISSIONS)
}
} else {
REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
baseContext,
it
) == PackageManager.PERMISSION_GRANTED
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Application authority
allPermissionsGranted()
}
}
So the whole Android The backup and restore of the local database is completed ,Demo I am the one who directly added to the original remote query analysis gadget Demo in 《 To make a Android Sqlite Remote operation and maintenance gadget 》, The complete source code is linked below :
Source code address
https://github.com/Vaccae/TransAndroidSqliteDBDemo.git
Click to read the original text and you can see “ Code cloud ” The address of
End
Past highlights
To make a Android Sqlite Remote operation and maintenance gadget
Realization Android Local Sqlite Database network transfer to PC End
Android Room Actual combat of database version migration
边栏推荐
- 手把手带你入门Apache伪静态的配置
- Lb10s-asemi rectifier bridge lb10s
- Principle and performance analysis of lepton lossless compression
- Simple page request and parsing cases
- LB10S-ASEMI整流桥LB10S
- Hiengine: comparable to the local cloud native memory database engine
- [cloud native] event publishing and subscription in Nacos -- observer mode
- 【Hot100】34. 在排序数组中查找元素的第一个和最后一个位置
- 一文详解ASCII码,Unicode与utf-8
- go 指针
猜你喜欢
Developers, is cloud native database the future?
The Research Report "2022 RPA supplier strength matrix analysis of China's banking industry" was officially launched
SAP SEGW 事物码里的 Association 建模方式
How to realize batch sending when fishing
【每日一题】1200. 最小绝对差
初次使用腾讯云,解决只能使用webshell连接,不能使用ssh连接。
C# 对象存储
Shu tianmeng map × Weiyan technology - Dream map database circle of friends + 1
一文详解ASCII码,Unicode与utf-8
将函数放在模块中
随机推荐
一文详解ASCII码,Unicode与utf-8
uni-app开发语音识别app,讲究的就是简单快速。
SAP SEGW 事物码里的 ABAP 类型和 EDM 类型映射的一个具体例子
LB10S-ASEMI整流桥LB10S
Simple page request and parsing cases
Changing JS code has no effect
Lb10s-asemi rectifier bridge lb10s
Principle and configuration of RSTP protocol
“百度杯”CTF比赛 九月场,Web:Upload
FPGA 学习笔记:Vivado 2019.1 添加 IP MicroBlaze
Apicloud studio3 API management and debugging tutorial
爱可生SQLe审核工具顺利完成信通院‘SQL质量管理平台分级能力’评测
[深度学习论文笔记]使用多模态MR成像分割脑肿瘤的HNF-Netv2
leetcode:221. Maximum square [essence of DP state transition]
Sorry, we can't open xxxxx Docx, because there is a problem with the content (repackaging problem)
Pandora IOT development board learning (HAL Library) - Experiment 7 window watchdog experiment (learning notes)
MATLAB论文图表标准格式输出(干货)
JXL notes
Navigation property and entityset usage in SAP segw transaction code
Notion 类笔记软件如何选择?Notion 、FlowUs 、Wolai 对比评测