【问题标题】:Export Room database and attach to email Android Kotlin导出 Room 数据库并附加到电子邮件 Android Kotlin
【发布时间】:2021-07-14 09:29:28
【问题描述】:

我有以下代码用于导出房间数据库,然后将其附加到电子邮件中。目前,用户首先必须选择他们希望数据保存在哪里才能附加。

有没有一种方法可以做到这一点,而无需先询问用户将数据库保存在哪里?

这是我的代码:

fun exportDatabase() {
        val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
        intent.type = "*/*" // this line is a must when using ACTION_CREATE_DOCUMENT
        startActivityForResult(
            intent,
            DATABASE_EXPORT_CODE
        )
    }

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
            DATABASE_EXPORT_CODE -> {
                val userChosenUri = data?.data
                val inStream = getDatabasePath("app_database").inputStream()
                val outStream = userChosenUri?.let { contentResolver.openOutputStream(it) }

                inStream.use { input ->
                    outStream.use { output ->
                        output?.let { input.copyTo(it) }
                        Toast.makeText(this, "Data exported successfully", Toast.LENGTH_LONG).show()
                        val emailIntent = Intent(Intent.ACTION_SEND)
                        //Set type to email
                        emailIntent.type = "vnd.android.cursor.dir/email"
                        var toEmail: String = "whatever@gmail.com"
                        emailIntent.putExtra(Intent.EXTRA_EMAIL, toEmail)
                        emailIntent.putExtra(Intent.EXTRA_STREAM, userChosenUri)
                        emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Data for Training Log")
                        startActivity(Intent.createChooser(emailIntent, "Send Email"))
                    }
                }

            }

            else ->
                Log.d("D001", "onActivityResult: unknown request code")
        }

    }

【问题讨论】:

    标签: android kotlin uri android-room android-fileprovider


    【解决方案1】:

    您需要使用FileProvider。但是FileProvider不支持直接传输数据库文件(Check here)。

    这可以通过以下方式处理:

    解决方案 1:

    创建一个支持复制数据库文件的自定义FileProvider类:

    class DBFileProvider : FileProvider {
        
        fun getDatabaseURI(c: Context, dbName: String?): Uri? {
            val file: File = c.getDatabasePath(dbName)
            return getFileUri(c, file)
        }
    
        private fun getFileUri(context: Context, file: File): Uri? {
            return getUriForFile(context, "com.android.example.provider", file)
        }
        
    }
    

    并在清单中请求FileProvider

    <application>
    
        ....
    
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.android.example.provider"
            android:exported="false"
            android:enabled="true"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/provider_paths" />
        </provider>
    
    </application>
    

    并在res\xml下创建provider_paths

    <?xml version="1.0" encoding="utf-8"?>
    
    <paths>
    
        <files-path
            name="databases"
            path="../" />
    
    </paths>
    

    然后通过电子邮件发送这个数据库文件:

    public static void backupDatabase(AppCompatActivity activity) {
        Uri uri = new DBFileProvider().getDatabaseURI(activity, "app_database.db");
        sendEmail(activity, uri);
    }
    
    private fun sendEmail(activity: AppCompatActivity, attachment: Uri) {
        val emailIntent = Intent(Intent.ACTION_SEND)
        //Set type to email
        emailIntent.type = "vnd.android.cursor.dir/email"
        val toEmail = "whatever@gmail.com"
        emailIntent.putExtra(Intent.EXTRA_EMAIL, toEmail)
        emailIntent.putExtra(Intent.EXTRA_STREAM, attachment)
        emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Data for Training Log")
        activity.startActivity(Intent.createChooser(emailIntent, "Send Email"))
    }
    

    解决方案 2:

    将数据库文件复制到一个临时文件到FileProvider支持的目录,比如filesDir

    • 使用getDatabasePath获取数据库文件
    • 将数据库文件复制到FileProvider支持的存储目录下
    • 使用FileProvider 创建新复制文件的 Uri
    fun backupDatabase(activity: AppCompatActivity) {
    
        // Get the database file
        val dbFile = activity.getDatabasePath("app_database.db")
    
        try {
    
            // Copy database file to a temp file in (filesDir)
            val parent = File(activity.filesDir, "databases_temp")
            val file = File(parent, "myDatabase")
            dbFile.copyTo(file)
    
            // Get Uri of the copied database file from filesDir to be used in email intent
            val uri = getUri(activity.applicationContext, file)
    
            // Send an email
            sendEmail(activity, uri)
    
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    
    
    private fun getUri(context: Context, file: File): Uri {
        var uri = Uri.fromFile(file)
    
        // Using FileProvider for API >= 24
        if (Build.VERSION.SDK_INT >= 24) {
            uri = FileProvider.getUriForFile(
                context,
                "com.android.example.provider", file
            )
        }
        return uri
    }
    

    使用解决方案1的相同清单。并使用创建的临时目录调整res\xml下的provider_paths

    <?xml version="1.0" encoding="utf-8"?>
    
    <paths>
        <files-path
            name="databases_temp"
            path="/" />
    </paths>
    

    注意:在这两种解决方案中,将包名称调整为您的。

    【讨论】:

      猜你喜欢
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 2021-11-18
      • 1970-01-01
      • 1970-01-01
      • 2018-03-30
      • 2016-12-29
      • 1970-01-01
      相关资源
      最近更新 更多