无法从函数内部返回变量

Not able to return variable from inside a function

提问人:Anurag Hale 提问时间:8/28/2022 更新时间:8/29/2022 访问量:52

问:

因此,我尝试从函数返回一个值以在 mainActivity 类中使用,但是当我尝试返回变量时出现错误,指出“变量必须初始化”,即使我已经为它指定了一个值。对此有什么想法吗?

private fun getCLocation() : LocationClass {

        var loc: LocationClass

        if(checkPermission()){

            if(isLocationEnabled()){

                locationVariable.lastLocation.addOnCompleteListener(this) { task->

                    val location:Location? = task.result

                    if(location == null){
                        Toast.makeText(this,"NULL",Toast.LENGTH_LONG).show()
                    }
                    else{
                        loc = LocationClass(location.latitude.toString(),location.longitude.toString())
                    }
                }

            } else {
                // location not enabled,open settings
                val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
                startActivity(intent)
            }

        } else {
            //Permission Not Enabled
            requestPermission()
        }

        return loc
    }

错误是:变量“loc”必须初始化

Android 函数 Kotlin 变量

评论

0赞 Anurag Hale 8/28/2022
@RoarS。我应该在这里分配什么作为“默认值”,因为 loc 是数据类型类型的变量,它不是字符串或 int
0赞 Anurag Hale 8/28/2022
@RoarS。我在尝试在 onCreate 函数中烘烤此变量时得到 null。但是在我设置了 loc 值的 else 正文中,我可以毫无错误地烘烤该值
1赞 Computable 8/28/2022
获取位置是在侦听器回调中获取的异步操作。列出的函数将永远无法返回除 null 之外的任何内容。
0赞 Anurag Hale 8/28/2022
@Gardener 关于如何将位置坐标返回给 OnCreate 方法,您有什么建议吗?
1赞 Tyler V 8/29/2022
这回答了你的问题吗?为什么调用 API 或启动协程的函数返回空值或 null 值?

答:

0赞 Tenfour04 8/29/2022 #1

代码的两个问题:

  1. 用户可能尚未授予权限,因此它将进入块,函数在其中请求权限,但不执行任何操作来设置初始位置值。在这种情况下,该函数不可能返回有效位置。else
  2. 获取位置更新是异步的。即使已授予权限,也要等到将来某个时间,在此函数已返回之后,才会调用 OnCompleteListener。您可以在此处阅读有关异步 API 的更多说明。

这是该做什么的基本策略。获取位置的函数采用回调参数,而不是直接返回 LocationClass,因为它是异步的。您需要一个更高级别的逻辑,可以在位置或权限可用后重试该逻辑。

private var triedPromptingLocationSetting = false
private var locationWorkflowInitiated = false // SET THIS BACK TO FALSE IN onViewDestroyed() IF IN FRAGMENT

private fun fetchCLocation(onReceived: (LocationClass?)->Unit) {
    if (!checkPermission() || isLocationEnabled()) {
        Log.e("Do not call getCLocation() before permission is granted and location is turned on! Ignoring.")
        return
    }
    locationVariable.lastLocation.addOnCompleteListener(this) { task->
        val location:Location? = task.result
        if (location == null) {
            onReceived(null)
        }
        else {
            var loc = LocationClass(location.latitude.toString(),location.longitude.toString())
            onReceived(loc)
        }
    }
}

// This is where the logic is for whatever you wanted to do with this location.
// In this example, it's assumed it would be called in onResume()
private fun doMyLocationWorkflow() {
    if (!checkPermission()) {
        requestPermission()
        return
    }
    if (!isLocationEnabled()) {
        if (triedPromptingLocationSetting) {
            // can't infinitely loop back to settings. 
            showSomeUiRequestingUserToManuallyEnableLocation()
        } else {
            triedPromptingLocationSetting = true
            val intent = Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)
            startActivity(intent)
        }
        return
    }

    locationWorkflowInitiated = true

    fetchCLocation { location ->
        if (location == null) {
            Toast.makeText(this,"NULL",Toast.LENGTH_LONG).show()
            //...
            return@fetchCLocation 
        }
        // Do something with the LocationClass
    }
}

override fun onResume() {
    super.onResume()
    if (!locationWorkflowInitiated) {
        doMyLocationWorkflow()
    }
}

private val locationPermissionRequest = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        when {
            permissions.getOrDefault(Manifest.permission.ACCESS_FINE_LOCATION, false) -> {
                doMyLocationWorkflow() // go back to original workflow
            }
            permissions.getOrDefault(Manifest.permission.ACCESS_COARSE_LOCATION, false) -> {
                doMyLocationWorkflow() // go back to original workflow
            } else -> {
                showSomeUiTellingUserPermissionMustBeGranted()
            }
        }
    }

private fun requestPermission() {
    locationPermissionRequest.launch(arrayOf(
    Manifest.permission.ACCESS_FINE_LOCATION,
    Manifest.permission.ACCESS_COARSE_LOCATION))
}