【问题标题】:How to get requestCode from Activity Result API如何从活动结果 API 获取 requestCode
【发布时间】:2021-06-08 12:22:25
【问题描述】:

我对 Android Kotlin 编程非常陌生。我正在制作一个使用存储访问框架创建、读取和删除文件的应用程序。我通过实现已弃用的 startActivityForResult 意图来执行文件读取、创建、删除任务来做到这一点。我尝试使用 Activity Result API 来实现它,但我陷入了找不到它的请求代码中。 在新的实现中,有 resultCode 但没有 requestCode。

我的实现如下。如何使用 Activity Result API 实现以下功能?

如何从 Activity Result API 获取请求代码?

fun createFile()
{
    val filename: String = etFileName.text.toString()
    val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
        type = "text/*"
        addCategory(Intent.CATEGORY_OPENABLE)
        putExtra(Intent.EXTRA_TITLE, filename)
    }
    startActivityForResult(intent, WRITE_REQUEST_CODE)
}


fun readFile(){
    etFileName.setText("")
    val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
        addCategory(Intent.CATEGORY_OPENABLE)
        type = "text/*"
    }
    startActivityForResult(intent, READ_REQUEST_CODE)
}

fun deleteFile(uri: Uri){
    val filename = queryName(contentResolver, uri)
    DocumentsContract.deleteDocument(contentResolver, uri)
    Toast.makeText(applicationContext, "Done deleting $filename", Toast.LENGTH_SHORT).show()
}

fun writeText(uri: Uri) : String{
    //var writetext: String = "typing high speed"
    var writeStream = contentResolver.openFileDescriptor(uri, "w")
    val filename: String = queryName(contentResolver, uri)
    etFileName.setText(filename)
    var fileOutputStream = FileOutputStream(writeStream?.fileDescriptor)
    fileOutputStream.write(filename.toByteArray())
    fileOutputStream.close()
    return filename.toString()
}

fun openFileContent(uri: Uri): String{
    val inputStream = contentResolver.openInputStream(uri)
    val reader = BufferedReader(InputStreamReader(inputStream))
    val stringBuilder = StringBuilder()

    val filename = queryName(contentResolver, uri)
    etFileName.setText(filename)
    var currentline = reader.readLine()

    while (currentline != null) {
        stringBuilder.append(currentline + "\n")
        currentline = reader.readLine()
    }
    inputStream?.close()
    val str =  stringBuilder.toString()
    Log.d("Uri Read", ": $str")
    return str
}

private fun queryName(resolver: ContentResolver, uri: Uri): String {
    val returnCursor: Cursor = resolver.query(uri, null, null, null, null)!!
    val nameIndex: Int = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
    returnCursor.moveToFirst()
    val name: String = returnCursor.getString(nameIndex)
    returnCursor.close()
    return name
}

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

    if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        val uri =resultData?.data
        Log.d("Uri Read", "$uri")
        if (uri != null) {
            val readfile: String = openFileContent(uri)
            etContent.setText(readfile)
        }
    } else if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        resultData?.data?.also { uri ->
            Log.i("Uri Write", "Uri: $uri")   // 1
            val write = writeText(uri)   // 2
            etContent.setText(write)
        }
    } else if (requestCode == DELETE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        val uri =resultData?.data
        Log.d("Uri Delete", "$uri")
        if (uri != null) {
            deleteFile(uri)
        }
    }
}

由于不推荐使用上述方法,我尝试使用 Intent 启动器来实现它,但在任何地方都没有对 requestCode 的引用,所以我被困在这里。如下图:

val startforFile: ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
    result: ActivityResult ->

    // could not find reference to requestCode here

    if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        val uri =resultData?.data
        Log.d("Uri Read", "$uri")
        if (uri != null) {
            val readfile: String = openFileContent(uri)
            etContent.setText(readfile)
        }
    } else if (requestCode == WRITE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        resultData?.data?.also { uri ->
            Log.i("Uri Write", "Uri: $uri")   // 1
            val write = writeText(uri)   // 2
            etContent.setText(write)
        }
    } else if (requestCode == DELETE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        val uri =resultData?.data
        Log.d("Uri Delete", "$uri")
        if (uri != null) {
            deleteFile(uri)
        }
    }
}

谁能告诉我它是如何正确完成的?

【问题讨论】:

    标签: android-studio kotlin android-intent activity-result-api


    【解决方案1】:

    ActivityResultContracts.StartActivityForResult 有两种方式。

    1. 通过注册多个监听器发出多个请求:
    val startForFileRead: ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
        result: ActivityResult ->
        if (resultCode == Activity.RESULT_OK) {
            val uri =resultData?.data
            Log.d("Uri Read", "$uri")
            if (uri != null) {
                val readfile: String = openFileContent(uri)
                etContent.setText(readfile)
            }
        } 
    }
    
    val startForFileWrite: ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
        result: ActivityResult ->
        if (resultCode == Activity.RESULT_OK) {
            resultData?.data?.also { uri ->
                Log.i("Uri Write", "Uri: $uri")   // 1
                val write = writeText(uri)   // 2
                etContent.setText(write)
            }
        } 
    }
    
    val startForFileDelete: ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){
        result: ActivityResult ->
        if (resultCode == Activity.RESULT_OK) {
            val uri =resultData?.data
            Log.d("Uri Delete", "$uri")
            if (uri != null) {
                deleteFile(uri)
            }
        } 
    }
    
    1. 在从其他活动返回的 Intent 中添加额外内容。将其解压缩为您的请求代码。
    const val REQUEST_CODE = "REQUEST_CODE"
    //...
    
    val startForFile: ActivityResultLauncher<Intent> =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        val requestCode = result.data?.extras?.getInt(REQUEST_CODE)
        if (requestCode == null) {
            Log.e("FileResultLauncher", "No REQUEST_CODE was returned in data intent.")
            return@registerForActivityResult
        }
        val uri = result.data?.data
        if (uri == null || result.resultCode != RESULT_OK) {
            Log.i("FileResultLauncher", "No Uri returned or result wasn't OK.")
            return@registerForActivityResult
        }
        when (requestCode) {
            READ_REQUEST_CODE -> {
                Log.d("Uri Read", "$uri")
                val readfile: String = openFileContent(uri)
                etContent.setText(readfile)
            }
            WRITE_REQUEST_CODE -> {
                Log.i("Uri Write", "Uri: $uri")   // 1
                val write = writeText(uri)   // 2
                etContent.setText(write)
            }
            DELETE_REQUEST_CODE -> {
                Log.d("Uri Delete", "$uri")
                deleteFile(uri)
            }
        }
    }
    

    【讨论】:

    • 感谢您的帮助。我遵循方法(1)[注册多个听众]并且它有效。我所做的轻微修改是通过在 result?.data? 末尾添加额外的 .data 来获取 uri? .我认为 result?.data 只返回了意图。所以我做到了 --> val uri = result?.data?.data.
    • 第二种方式不行!
    • @kitfist0 我测试了它,它运行良好。如果您在第二个活动中使用请求代码,请确保将其作为额外内容添加到您传递给launch() 的 Intent 中,以便您可以从第二个活动中收到的意图中解压缩它。并在结果中设置它,在您对setResult() 的调用中添加一个带有额外请求代码的 Intent。
    • @Tenfour04 那么系统设置活动呢?此外,最近流行单一活动方法。
    • 您通常不会打开系统设置活动来响应,是吗?如果有任何确实给出了响应,我想您必须坚持使用旧的结果方法活动,尽管现在已弃用,直到 Jetpack 为它们提供合同。当您可以使用单活动方法时,它确实是一个好主意。有时它不适合模块化,例如,如果您想打开自己的条形码扫描仪,该扫描仪具有完全不同的 UI,没有操作栏等。将其放在单独的 Activity 中更有意义。
    猜你喜欢
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多