How To Read Version Number From A Database File In Android Which Is Placed In Asset Folder
Solution 1:
There is not a single version number, instead version number could be multiple values.
At a guess you are talking abut the user_version which the Android SDK SQLiteOpenHelper uses.
There is also the application_id, which like the user_version can be used as a user variable.
You've already encountered the SQLite_Version, so that can be discounted.
There is also the data_version, this is unlikely to be the version number, as it's intended to be used as an indication if the database file has been modified in real time.
There is also the schema_version, you probably DO NOT want to use this as Warning: Misuse of this pragma can result in database corruption.
user_version
As previously said you are probably talking about the user_version. The first thing to note is that it is a user controlled variable/field made available for custom use. SQlite does not use or change the user_version but does allow it to be changed and used.
Furthermore SQLite Managers (such as DB Browser, Navicat etc) would not automatically change the version number. As such you would have to intentionally change the the user_version for it to be available before copying the database file into the assets folder (noting that if doing so and you are using a subclass of SQLiteOpenHelper
that the onUpgrade
and the onDowngrade
methods may be called).
If the user_version is not specifically changed and the database was only accessed by the SQLite Manager tool then it's user_version will be 0. If the database file was opened by copying the database file from an Android App that utilises a subclass of SQLiteOpenHelper the it will have a user_version of 1 or more (depending upon the last value used as the 4th parameter to the SQLiteOpenHelper's constrcutor). Of course if the user_version is changed programatically then such a change would also be reflected if the file were copied into a SQlite Manager tool.
Before copying the file the user_version would typically be changed within the SQlite Manager tool to an appropriate value.
You can change the user_version using the SQL PRAGMA user_version = 5;
You can retrieve the user_version using either PRAGMA user_version
or SELECT * FROM pragma_user_version;
If you need to check the version before opening the database then you could read the 4 bytes at offset 60 and convert the 4 bytes to an integer, to check the user_version against another value. Otherwise you'd probably have to copy the file, likely using a different name, from the assets folder, open it as an SQLiteDatabase and retrieve the user_version using the SQL above and then check it against the other value, closing the database file. The deleting the file if not needed, otherwise deleting the prior database file and then renaming the copied file.
Example
The following is a working example (noting that I rarely use Kotlin and this has been converted using AS studio from java).
This uses a class, namely SQLAssetVersionCheck that extracts the version number from the file rather than opening the file as an SQLiteDatabase.
SQLAssetVersionCheck.kt :-
classSQLAssetVersionCheck/**
* 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 = 0privatesetvar result: Int = 0privatesetinit {
assetPath = applySubDirectories(databaseName, subDirectories)
Log.d("SQLAVC", "Looking for Asset $assetPath")
var stage = 0try {
val `is` = context.assets.open(assetPath)
stage++
// Get the first 64 bytes of the headerval v = ByteArray(64)
`is`.read(v, 0, 64)
// only interested in the 4 bytes from offset 60 so get themval v2 = ByteArray(4)
for (i in60..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) {}
privatefunapplySubDirectories(dbname: String, subDirectories: Array<String>?): String {
val base = StringBuffer("")
var firstdirectory = trueif (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()
}
companionobject {
val ASSETNOTFOUND = -2val ASSETIOERROR = -3val ASSETVERSIONMATCH = 0val ASSETVERSIONHIGH = 1val ASSETVERSIONLOW = -1
}
}
And here's an Activity that uses the above class twice to try to check the version in the testdb file.
The first usage doesn't find the database file testdb as it is looking in assets folder (not the databases sub-directory).
The second usage finds the testdb file as the sub-directory databases is specified (3rd parameter of the full constructor), finding in the assets/databases/ folder i.e. assets/databases/testdb :-
MainActivity.kt :-
classMainActivity : AppCompatActivity() {
overridefunonCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db_version_to_check_against = 100var 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")
}
}
Result (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
The first attempt doesn't find the file (the exception that was caught is displayed) and displays the line The result of the version check was - The Asset, for Database testdb was not located at testdb to be displayed.
The second attempt works and results in 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
The gap of blanks lines was added to split the second attempt from the first.
Additional
After using the SQLite Manager tool (Navicat) and using :-
PRAGMAuser_version=101;
Then copying the file (after closing the connection in Navicat) to the assets folder (so I have two testdb files) then the result is :-
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
- i.e. the new file has the user_version as 101 and so the first finds the file, the second finds the file (user_version 5) as before.
Post a Comment for "How To Read Version Number From A Database File In Android Which Is Placed In Asset Folder"