Kotlin:无法调用表达式,因为找不到函数 invoke()



我正在尝试构建一个实现谷歌地图的应用程序。由于某种原因,我得到了一个错误,因为找不到函数invoke((,所以无法调用表达式。我不知道该怎么解决也许你们中的一个能帮忙?

package com.example.maxs.kotlinnearbyv2
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.example.maxs.kotlinnearbyv2.Common.Common
import com.example.maxs.kotlinnearbyv2.Model.MyPlaces
import com.example.maxs.kotlinnearbyv2.Remote.IGoogleAPIService
import com.google.android.gms.maps.*
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import kotlinx.android.synthetic.main.activity_maps.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mMap: GoogleMap
private var latitude:Double=0.toDouble()
private var longitude:Double=0.toDouble()
lateinit var mService:IGoogleAPIService
internal var currentPlace: MyPlaces?=null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
val mapFragment = supportFragmentManager
.findFragmentById(R.id.map) as SupportMapFragment
mapFragment.getMapAsync(this)
//Init Service
mService = Common.googleApiService
bottom_navigation_view.setOnNavigationItemReselectedListener {item ->
when(item.itemId)
{
R.id.action_hospital -> nearByPlace("hospital")
R.id.action_restaurant -> nearByPlace("restaurant")
R.id.action_market -> nearByPlace("market")
R.id.action_school -> nearByPlace("school")
}
}
}
private fun nearByPlace(typePlace: String) {
//Clear all marker on Map
mMap.clear()
//build URL request base on location
val url = getUrl(latitude,longitude, typePlace)
mService.getNearByPlaces(url)
.enqueue(object : Callback<MyPlaces>{
override fun onResponse(call: Call<MyPlaces>, response: Response<MyPlaces>) {
currentPlace = response.body()
if(response!!.isSuccessful)
{
for(i in 0 until response!!.body()!!.results!!.size)
{
val markerOptions=MarkerOptions()
val googlePlace = response.body().results!!(i)
val lat = googlePlace.geometry!!.location!!.lat
val lng = googlePlace.geometry!!.location!!.lng
val placeName = googlePlace.name
val latLng = LatLng(lat, lng)
markerOptions.position(latLng)
markerOptions.title(placeName)
if (typePlace.equals("hospital"))
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_local_hospital_black_24dp))
else if (typePlace.equals("market"))
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_shopping_cart_black_24dp))
else if (typePlace.equals("restaurant"))
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_restaurant_black_24dp))
else if (typePlace.equals("school"))
markerOptions.icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_school_black_24dp))
else
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
markerOptions.snippet(i.toString())
//add marker to map
mMap!!.addMarker(markerOptions)

}
//move camera
mMap!!.moveCamera(CameraUpdateFactory.newLatLng(LatLng(latitude, longitude)))
mMap!!.animateCamera(CameraUpdateFactory.zoomTo(15.0f))
}
}
override fun onFailure(call: Call<MyPlaces>, t: Throwable) {
Toast.makeText(baseContext, ""+t!!.message,Toast.LENGTH_SHORT).show()
}
})
}
private fun getUrl(latitude: Double, longitude: Double, typePlace: String): String {
val googlePlaceUrl = StringBuilder("https://maps.googleapis.com/maps/api/place/nearbysearch/json")
googlePlaceUrl.append("?location=$latitude,$longitude")
googlePlaceUrl.append("&radius=10000") //10 km
googlePlaceUrl.append("&type=$typePlace")
googlePlaceUrl.append("&key=")
Log.d("URL_DEBUG", googlePlaceUrl.toString())
return googlePlaceUrl.toString()
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
override fun onMapReady(googleMap: GoogleMap) {
mMap = googleMap
// Add a marker in Sydney and move the camera
val barbier = LatLng(52.391274, 6.449712)
mMap.addMarker(MarkerOptions().position(barbier).title("Marker in Barbier"))
mMap.moveCamera(CameraUpdateFactory.newLatLng(barbier))
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(barbier, 15.0f))
}
}

我似乎找不到任何解决方案,我可能正在想办法解决…错误出现在response.body((!!上!!。后果(i(

val googlePlace = response.body().results!!(i)

现在我真的快疯了。

要访问数组或列表中的元素,请使用方括号,例如:

array[i]
list[i] // or list.get(i)
results!![i]

关于错误消息:Kotlin假设了一个invoke运算符,但您没有提供。您可能想了解invoke运算符的优点。有时它很方便。但对于你的问题,方括号应该足够了。

作为(进一步的(旁注:不要用大量的!!编写代码,而是首先尝试确定什么可以是null,如果不适合您的需求,则省略其余部分,例如:

response?.also {
if (it.isSuccessful) {
it.body()?.results?.forEach {
//...
}
}
}

只是一个开始。。。然后你可能想把事情简化得更简单。。。只要有可能就省略!!。。。您可能还想了解Kotlin中的空安全性,也许还想了解智能铸造。

您的typePlace.equals(...-条件也可以完全替换为when,例如:

when(typePlace) {
"hospital" -> ...
"market" -> ...

letalso相结合可能会进一步减少代码,但这可能是另一回事,更适合代码审查。

正如Roland所提到的,()是调用运算符,[]是索引运算符。()用于以下功能:

fun demo(func: (i: Int) -> Unit){
// These are identical
func(1)
func.invoke(1)
}

[]是索引运算符,这就是您想要在这里应用的。

它可以用于任何具有operator fun get(args)的类

class Demo {
// These don't actually need a return type either. Or any arguments at all. 
// If this was an int-containing class (i.e. a List), this would be the conventional declaration
operator fun get(index: Int) : Int {
return 0 // Obviously with an actual return value. 
}
// But they don't have to. They can have multiple, or no arguments. 
operator fun get(index: Int, fallback: Int) : Int{
return fallback
}
}
fun test(){
val demo = Demo()
//Depending on arguments, the use is different. Single-arg is basic, and traditional:
val value = demo[12];
// But the multi-arg one can be useful depending on the class.
val value2 = demo[12, 3];
}

我知道你没有问过要声明这些,但代码是我观点的一部分:

  • 索引运算符应用于具有operator fun get的任何类,具有任何数量的输入参数
  • 列表、映射和数组都有这种方法

所以您希望使用[index],而不是(index)。或者,您可以使用该方法,并直接使用.get(index)。如果要使用空安全调用(?.(,则必须使用.get(index)

此外,与使用null断言相比,您通常应该更喜欢null安全调用(可选地与?.let{ }?.forEach { }或类似调用组合(。首先,它有点违背了Kotlin的核心部分之一:零安全。其次,如果它为空,应用程序将崩溃,而不是优雅地告诉用户"出了问题"。我不熟悉你正在使用的库,所以老实说,我不确定什么时候是空的,即使成功了,它是否也可以是空的。

至于letforEach,当您具有可空性时,它们更容易使用。考虑一下:

someNullableIterable?.forEach {
// Only invoked if the iterable isn't null
}

与相比

if(someNullableIterable!= null){
for(item in someNullableIterable!!) { // Needs !! if the variable is global, and it's a var and not a val. 
// Foo bar
}
}

还有很多类似的函数,如果你也需要使用索引,还有forEachIndexed。但是,仅仅使用forEach(或者forEachIndexed(将缩短一些代码,并更好地允许您处理可空性。

最新更新