【问题标题】:Download external .db file for read-only use in Kotlin Android application?下载外部 .db 文件以在 Kotlin Android 应用程序中只读使用?
【发布时间】:2019-09-12 16:33:24
【问题描述】:

我已经有一个 SQLite 数据库 (.db) 文件可在特定 URL(假设为 https://mywebsite.com/mydb.db)下载。我想下载这个文件并在我的 Kotlin Android 应用程序中使用它。我可以将文件下载到我的设备模拟器中的“下载”文件夹,但我有几个关于从这里去哪里的问题。

  1. 我需要将此文件复制到内部存储,还是可以直接从“下载”文件夹中的文件创建数据库?我希望数据库数据保留在本地,因此我不想将数据库文件留在可能会被删除的地方(下载文件夹)。

    • 基本上,我希望应用能够从持久的内部 .db 文件中读取数据
  2. 有时,我需要向.db 文件添加更多数据。将来,当我重新下载.db 文件并从中创建数据库时,这会覆盖应用程序内部存储中的现有数据库吗?我是否需要手动删除数据库的旧迭代?

  3. 我想在应用程序第一次运行时自动下载.db文件,并且每次我将.db文件的新版本上传到https://mywebsite.com/mydb.db。

    李>

总的来说,我对 Android 开发非常陌生,所以我不确定最佳实践是什么。我提供的代码通过单击按钮将我的.db 文件成功下载到“下载”文件夹。从.db 文件创建数据库以及在我将新的.db 文件上传到我的主机 URL 时自动替换数据库方面,我不知道从哪里开始。

private const val PERMISSION_CODE = 1000

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        downloadButton.setOnClickListener {
            // Checks if version of Android is >= Marshmallow
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED){
                    // request permission if denied
                    requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), PERMISSION_CODE)
                }
                else {
                    startDownload()
                }
            }
            else {
                // OS is out of date, no permissions are needed
                startDownload()
            }
        }

private fun startDownload() {
        val request = DownloadManager.Request(Uri.parse(getString(R.string.db_URL)))
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
        request.setTitle("my_database.db")
        request.setDescription("My database is downloading.")
        request.allowScanningByMediaScanner()
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "mydb_" + "${System.currentTimeMillis()}")

        val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        manager.enqueue(request)
}

【问题讨论】:

    标签: android kotlin download android-sqlite android-internal-storage


    【解决方案1】:

    我需要将此文件复制到内部存储,还是可以直接从下载文件夹中的文件创建数据库?

    该文件是数据库,因此可以从下载文件夹中打开。

    我希望数据库数据保留在本地,因此我不想将数据库文件留在可能会被删除的地方(下载文件夹)。

    您可以根据Context的getDatabasePath(the_database_name)方法从下载文件夹中复制文件并将其放置在应用程序的默认位置,以获取文件将被复制到的位置.您将(至少在第一次运行时)检查数据库文件是否存在于其最终位置,然后启动副本,之后可以打开和使用数据库。

    或者,您可以将其直接下载到最终目的地,而不是使用中间副本。

    有时,我需要向 .db 文件添加更多数据。将来,当我重新下载 .db 文件并从中创建数据库时,这会覆盖应用程序内部存储中的现有数据库吗?我需要手动删除数据库的旧迭代吗?

    有多种方法,但基本上如果引入一个新文件,那么您可能会覆盖旧位置的现有数据库文件(存储在应用程序的数据中)(尽管这不是唯一的选择)。虽然,如果引入新数据而不是新模式(后者可能需要新代码,以便您可以利用数据库版本强制重新复制)。

    问题是如何知道是否引入了新文件,因为至少在最终目的地,数据库文件名可能相同。

    1. 检查文件的大小可能不会在发生更改时表示更改,因此不是故障安全选项。

      • 即数据库文件保存为页面,其中一些页面可能包含更新数据库时可能使用的可用空间,因此数据库文件大小保持不变。
    2. 您可以查看文件的最后修改日期。

    3. 您可以使用不同的文件名,例如mydbv1.db 然后是 mydbv2.db 等等。
    4. 您可以使用 user_version,如果使用 SQLiteOpenHelper 的子类(通常是这种情况),则需要小心,因为 SQLiteOpenHelper 会使用该子类(作为第 4 个参数传递的数据库版本)。
    5. 您可以使用 application_id(这类似于 user_version 但 SQLiteOpenHelper 不使用)。

    1-3 需要一种持久记录当前使用值的方法,可能在数据库本身的表中,也可能是同一目录中的空文件。

    4 & 5 实际上存储在数据库标题中,您可以通过编译指示访问值或以编程方式提取它们(后者不需要将文件作为数据库打开,并且通常资源密集度较低,因为您只需要阅读前 100 个字节以获得完整的标头)。

    一旦您检测到新版本,只需重新下载和复制即可。

    以上假设应用程序有多个用户,因此下载文件必须始终存在于主机服务器(您的网站)上,并且您已将应用程序与数据库一起提供折扣(这可以简化问题,例如当一个新的版本可用您引入新版本的应用程序)。

    上面还假设数据库只能由最终用户读取。如果没有,并且用户可以更新数据,则需要一种策略来满足保留特定用户的数据。

    【讨论】:

      猜你喜欢
      • 2022-09-23
      • 1970-01-01
      • 2011-10-31
      • 2017-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-25
      相关资源
      最近更新 更多