我正在尝试构建一个用于实现Google地图的应用。由于某种原因,我收到错误消息,因为找不到函数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()!!。results !!(i)
val googlePlace = response.body().results!!(i)
肯定现在让我发疯了。
答案 0 :(得分:2)
要访问数组或列表中的元素,请使用方括号,例如:
function write(isbn, title, author, issued) {
const fs = require(['fs'], function (fs){
const data = fs.readFileSync('js/book.json');
let jsonStr = data.toString();
const obj = JSON.parse(jsonStr);
obj.books.push({
isbn,
title,
author,
issued,
});
jsonStr = JSON.stringify(obj);
console.log(jsonStr);
fs.truncate('js/book.json', 0, () => {
fs.writeFile('js/book.json', jsonStr, (err) => {
if (err) {
throw new Error(`Error writing file: ${err}`);
}
});
});
});
}
关于错误消息:Kotlin假设您没有提供invoke operator。您可能需要阅读invoke-operator的优点。有时它非常方便。但是对于您的问题,方括号就足够了。
作为(更多)补充说明:不要用大量的array[i]
list[i] // or list.get(i)
results!![i]
来编写代码,而是首先尝试确定!!
可能是什么,如果没有,则忽略其余的内容不能满足您的需求,例如:
null
只是一个开始...您可能然后想进一步简化事情...只要可能就省略response?.also {
if (it.isSuccessful) {
it.body()?.results?.forEach {
//...
}
}
}
...您可能还想读一下null safety in Kotlin,也许还想smart casts。
您的!!
-条件也可以完美地替换为when
,例如:
typePlace.equals(...
与when(typePlace) {
"hospital" -> ...
"market" -> ...
或let
结合使用甚至可以进一步减少您的代码,但这可能是另一个故事,更适合code review。
答案 1 :(得分:1)
如Roland所述,()
是调用运算符,而[]
是索引运算符。 ()
用于以下功能:
fun demo(func: (i: Int) -> Unit){
// These are identical
func(1)
func.invoke(1)
}
[]
是index operator,这就是您要在此处应用的内容。
它可用于具有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的核心部分之一:空安全性。其次,如果它曾经为null,则该应用程序将崩溃,而不是优雅地告诉用户“出了点问题”。我不熟悉您正在使用的库,因此,老实说,我不确定什么时候为null,即使成功也可以为null。
对于let
和forEach
,当您具有可空性时,它们将更易于使用。考虑一下:
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
)将缩短您的某些代码,并更好地使您处理可空性。