Nie ma jednego numeru wersji, zamiast tego numer wersji może zawierać wiele wartości.
Przypuszczam, że mówisz o wersji_użytkownika którego używa Android SDK SQLiteOpenHelper.
Istnieje również application_id , która podobnie jak user_version może być używana jako zmienna użytkownika.
Napotkałeś już SQLite_Version, więc możesz to zdyskontować.
Istnieje również data_version, jest to mało prawdopodobne, aby był to numer wersji, ponieważ ma służyć jako wskazówka, czy plik bazy danych został zmodyfikowany w czasie rzeczywistym.
Istnieje również wersja schema_version, prawdopodobnie NIE chcesz jej używać jako Ostrzeżenie:niewłaściwe użycie tej pragmy może spowodować uszkodzenie bazy danych.
wersja_użytkownika
Jak wcześniej wspomniano, prawdopodobnie mówisz o wersji_użytkownika . Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że jest to zmienna/pole kontrolowane przez użytkownika udostępniane do użytku niestandardowego. SQlite nie używa ani nie zmienia user_version ale pozwala na jego zmianę i używanie.
Ponadto menedżery SQLite (takie jak DB Browser, Navicat itp.) nie zmienią automatycznie numeru wersji. W związku z tym musiałbyś celowo zmienić wersję_użytkownika, aby była dostępna przed skopiowaniem pliku bazy danych do folderu zasobów (zauważ, że jeśli to zrobisz i używasz podklasy SQLiteOpenHelper
że onUpgrade
i onDowngrade
mogą być wywoływane metody).
Jeśli wersja_użytkownika nie została specjalnie zmieniona, a do bazy danych uzyskano dostęp tylko za pomocą narzędzia SQLite Manager, jego wersja_użytkownika będzie wynosić 0. Jeśli plik bazy danych został otwarty przez skopiowanie pliku bazy danych z aplikacji na Androida, która wykorzystuje podklasę SQLiteOpenHelper, będzie miał user_version 1 lub więcej (w zależności od ostatniej wartości użytej jako czwarty parametr w constrcutorze SQLiteOpenHelper). Oczywiście, jeśli user_version zostanie zmieniona programowo, taka zmiana zostanie również odzwierciedlona, jeśli plik zostanie skopiowany do narzędzia SQLlite Manager.
Przed skopiowaniem pliku nazwa_użytkownika byłaby zazwyczaj zmieniana w narzędziu SQlite Manager na odpowiednią wartość.
Możesz zmienić wersję_użytkownika używając SQL PRAGMA user_version = 5;
Możesz pobrać user_version używając PRAGMA user_version
lub SELECT * FROM pragma_user_version;
Jeśli potrzebujesz sprawdzić wersję przed otwarciem bazy danych, możesz odczytać 4 bajty pod offsetem 60 i przekonwertować 4 bajty na liczbę całkowitą, aby sprawdzić user_version z inną wartością. W przeciwnym razie prawdopodobnie będziesz musiał skopiować plik, prawdopodobnie używając innej nazwy, z folderu zasobów, otworzyć go jako SQLiteDatabase i pobrać wersję_użytkownika za pomocą powyższego SQL, a następnie porównać go z inną wartością, zamykając plik bazy danych. Usunięcie pliku, jeśli nie jest potrzebne, w przeciwnym razie usunięcie poprzedniego pliku bazy danych, a następnie zmiana nazwy skopiowanego pliku.
Przykład
Poniżej znajduje się działający przykład (zauważ, że rzadko używam Kotlina i został on przekonwertowany przy użyciu AS studio z javy).
To używa klasy, a mianowicie SQLAssetVersionCheck który wyodrębnia numer wersji z pliku, zamiast otwierać plik jako SQLiteDatabase.
SQLAssetVersionCheck.kt :-
class SQLAssetVersionCheck
/**
* Full SQLAssetVersionCheck Constructor - sub directories can be specified
* @param context Assets are part of package so use the context to get the asset file
* @param dbName The database name (i.e. the file name)
* @param subDirectories The sub-directories as per the heirarchial order
* @param dbVersion The database version to check against
*/
(context: Context, val databaseName: String, subDirectories: Array<String>?, dbVersion: Int) {
val assetPath: String
var databaseVersion: Int = 0
private set
var result: Int = 0
private set
init {
assetPath = applySubDirectories(databaseName, subDirectories)
Log.d("SQLAVC", "Looking for Asset $assetPath")
var stage = 0
try {
val `is` = context.assets.open(assetPath)
stage++
// Get the first 64 bytes of the header
val v = ByteArray(64)
`is`.read(v, 0, 64)
// only interested in the 4 bytes from offset 60 so get them
val v2 = ByteArray(4)
for (i in 60..63) {
v2[i - 60] = v[i]
}
stage++
// Done with the InputStream so close it
`is`.close()
// Extarct the stored DBVersion
databaseVersion = ByteBuffer.wrap(v2).int
if (databaseVersion < dbVersion) {
result = ASSETVERSIONLOW
}
if (databaseVersion > dbVersion) {
result = ASSETVERSIONHIGH
}
if (databaseVersion == dbVersion) {
result = ASSETVERSIONMATCH
}
} catch (e: IOException) {
e.printStackTrace()
when (stage) {
0 -> result = ASSETNOTFOUND
1 -> result = ASSETIOERROR
}
}
}
constructor(context: Context, dbName: String, dbVersion: Int) : this(context, dbName, null, dbVersion) {}
private fun applySubDirectories(dbname: String, subDirectories: Array<String>?): String {
val base = StringBuffer("")
var firstdirectory = true
if (subDirectories != null) {
for (d in subDirectories) {
if (!firstdirectory) {
base.append(File.separatorChar)
}
firstdirectory = false
base.append(d)
}
}
if (base.length > 0) {
base.append(File.separatorChar)
}
base.append(dbname)
return base.toString()
}
companion object {
val ASSETNOTFOUND = -2
val ASSETIOERROR = -3
val ASSETVERSIONMATCH = 0
val ASSETVERSIONHIGH = 1
val ASSETVERSIONLOW = -1
}
}
A oto Aktywność, która używa powyższej klasy dwukrotnie, aby spróbować sprawdzić wersję w testdb plik.
-
Pierwsze użycie nie powoduje znalezienia pliku bazy danych testdb jak szuka w aktywach folder (nie podkatalog baz danych).
-
Drugie użycie znajduje testdb plik jako podkatalog bazy danych jest określony (3. parametr pełnego konstruktora), znajdujący się w assets/databases/ folder, tj. assets/databases/testdb :-
Aktywność główna.kt :-
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db_version_to_check_against = 100
var mAVC1 = SQLAssetVersionCheck(this, "testdb", 100)
var result = ""
when (mAVC1.result) {
SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC1.databaseName + " was not located at " + mAVC1.assetPath
SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
mAVC1.databaseVersion.toString() +
" was higher than the version to be checked which was " +
db_version_to_check_against.toString()
SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
mAVC1.databaseVersion.toString() +
" was lower than the version to be checked which was " +
db_version_to_check_against.toString()
SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
}
Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")
var mAVC2 = SQLAssetVersionCheck(this, "testdb", arrayOf("databases"), db_version_to_check_against)
result = ""
when (mAVC2.result) {
SQLAssetVersionCheck.ASSETIOERROR -> result = "IO ERROR detected - check the Log"
SQLAssetVersionCheck.ASSETNOTFOUND -> result = "The Asset, for Database " + mAVC2.databaseName + " was not located at " + mAVC2.assetPath
SQLAssetVersionCheck.ASSETVERSIONHIGH -> result = "The Asset was located and the version number being " +
mAVC2.databaseVersion.toString() +
" was higher than the version to be checked which was " +
db_version_to_check_against.toString()
SQLAssetVersionCheck.ASSETVERSIONLOW -> result = "The Asset was located and the version number being " +
mAVC2.databaseVersion.toString() +
" was lower than the version to be checked which was " +
db_version_to_check_against.toString()
SQLAssetVersionCheck.ASSETVERSIONMATCH -> result = "The Asset version and the version to be check ed are the same."
}
Log.d("ASSETVERSIONCHECK", "The result of the version check was - $result")
}
}
Wynik (log):-
2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:11:34.473 19058-19058/com.example.so54741423assetdbversioning W/System.err: java.io.FileNotFoundException: testdb
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.content.res.AssetManager.nativeOpenAsset(Native Method)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.content.res.AssetManager.open(AssetManager.java:744)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.content.res.AssetManager.open(AssetManager.java:721)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err: at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:31)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err: at com.example.so54741423assetdbversioning.SQLAssetVersionCheck.<init>(SQLAssetVersionCheck.kt:67)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err: at com.example.so54741423assetdbversioning.MainActivity.onCreate(MainActivity.kt:17)
2019-02-19 13:11:34.474 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.Activity.performCreate(Activity.java:7136)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.Activity.performCreate(Activity.java:7127)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.os.Handler.dispatchMessage(Handler.java:106)
2019-02-19 13:11:34.475 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.os.Looper.loop(Looper.java:193)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6669)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset, for Database testdb was not located at testdb
2019-02-19 13:11:34.476 19058-19058/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:11:34.477 19058-19058/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
-
Pierwsza próba nie znajduje pliku (wyświetlany jest wyjątek, który został wyłapany) i wyświetla wiersz Wynikiem sprawdzania wersji był - Zasób bazy danych testdb nie znajdował się w testdb do wyświetlenia.
-
Druga próba działa i daje Wynik sprawdzania wersji był następujący:Zasób został zlokalizowany, a numer wersji równy 5 był niższy niż wersja do sprawdzenia, która wynosiła 100
-
Dodano odstęp pustych linii, aby oddzielić drugą próbę od pierwszej.
Dodatkowe
Po użyciu narzędzia SQLite Manager (Navicat) i użyciu :-
PRAGMA user_version = 101;
Następnie kopiowanie pliku (po zamknięciu połączenia w Navicat) do folderu asset (więc mam dwa pliki testdb) to wynik to :-
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 101 was higher than the version to be checked which was 100
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/SQLAVC: Looking for Asset databases/testdb
2019-02-19 13:50:09.874 19253-19253/com.example.so54741423assetdbversioning D/ASSETVERSIONCHECK: The result of the version check was - The Asset was located and the version number being 5 was lower than the version to be checked which was 100
- tj. nowy plik ma wersję user_version 101, więc pierwszy znajduje plik, drugi znajduje plik (user_version 5) jak poprzednio.