Котлин: Выражение не может быть вызвано, потому что функция invoke () не найдена - PullRequest
0 голосов
/ 31 октября 2018

Я пытаюсь создать приложение, в котором я использую карты 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 () !!. результаты !! (i)

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

это точно сводит меня с ума прямо сейчас.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Как упоминал Роланд, () - это оператор вызова, а [] - оператор индекса. () используется, помимо прочего, для функций:

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).

Кроме того, вы, как правило, предпочитаете нулевые безопасные вызовы, опционально комбинируемые с ?.let{ }, ?.forEach { } или аналогичными, вместо использования нулевого подтверждения. Прежде всего, это своего рода победа над одной из основных частей Kotlin: нулевая безопасность. Во-вторых, если оно когда-либо будет нулевым, приложение будет зависать, вместо того, чтобы изящно сказать пользователю «Что-то пошло не так». Я не знаком с библиотекой, которую вы используете, поэтому честно говоря, я не уверен, что когда null, и может ли он быть нулевым, даже если он успешен.

Что касается let и forEach, их проще использовать, когда у вас есть Nullability. Учтите это:

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) сократит часть вашего кода и позволит вам лучше справляться с обнуляемостью.

0 голосов
/ 31 октября 2018

Чтобы получить доступ к элементу в массиве или списке, используйте квадратные скобки, например ::

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

Относительно сообщения об ошибке: Kotlin предполагал оператор вызова , который вы не предоставили. Вы можете прочитать, для чего хорош оператор invoke. Иногда это очень удобно. Но для вашей задачи должно хватить квадратных скобок.

В качестве (дополнительного) примечания: не пишите свой код с тоннами !!, попробуйте сначала определить, что может быть null, и пропустите все остальное, если оно не подходит вашему потребности, например:

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

Просто для начала ... вы можете захотеть еще больше упростить вещи ... Просто опустите !!, когда это возможно ... Вы также можете прочитать о нулевой безопасности в Kotlin и, возможно, также о умных приведениях .

Ваши typePlace.equals(... -условия также могут быть полностью заменены на when, например ::

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

Это в сочетании с let или also может еще больше уменьшить ваш код, но, вероятно, это будет другая история, лучше подходящая для обзора кода .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...