Kotlin: Antarmuka ... tidak memiliki konstruktor

138

Saya mengubah beberapa kode Java saya ke Kotlin dan saya tidak begitu mengerti bagaimana cara membuat antarmuka yang didefinisikan dalam kode Kotlin. Sebagai contoh, saya memiliki antarmuka (didefinisikan dalam kode Java):

public interface MyInterface {
    void onLocationMeasured(Location location);
}

Dan kemudian lebih lanjut dalam kode Kotlin saya, saya instantiate antarmuka ini:

val myObj = new MyInterface { Log.d("...", "...") }

dan itu bekerja dengan baik. Namun, ketika saya mengonversi MyInterface ke Kotlin:

interface MyInterface {
    fun onLocationMeasured(location: Location)
}

Saya mendapatkan pesan kesalahan: Interface MyListener does not have constructorsketika saya mencoba untuk instantiate - meskipun menurut saya tidak ada yang berubah kecuali sintaksis. Apakah saya salah mengerti bagaimana antarmuka bekerja di Kotlin?

Aleph Aleph
sumber

Jawaban:

225

Kode Java Anda bergantung pada konversi SAM - konversi otomatis lambda ke antarmuka dengan metode abstrak tunggal. Konversi SAM saat ini tidak didukung untuk antarmuka yang ditentukan di Kotlin. Sebagai gantinya, Anda perlu mendefinisikan objek anonim yang mengimplementasikan antarmuka:

val obj = object : MyInterface {
    override fun onLocationMeasured(location: Location) { ... }
}
Yole
sumber
14
Terimakasih banyak. Dari tautan yang Anda poskan, saya mengerti bahwa lebih baik menggunakan tipe fungsional (misalnya Location -> Unit) daripada antarmuka metode tunggal jika mungkin - apakah itu benar?
Aleph Aleph
4
Itu benar. Anda harus menggunakan tipe fungsional sedapat mungkin.
Yoav Sternberg
Namun dalam kasus saya antarmuka (SurfaceTextureListener) memiliki banyak metode.
Tash Pemhiwa
Terima kasih banyak. Jawaban ini harus memiliki lebih banyak suka atau tanda khusus, berikan informasi yang sangat berguna dan sayangnya beberapa pelajar dapat menjadi sangat bingung ketika mempelajari Kotlin dengan artikel atau dengan "Kotlin in Action" ketika mereka melihat topik SAM.
TT_W
dari "Kotlin in Action", ya, Anda dapat menggunakan lambda dalam parameter SAM Java untuk mempersingkat dan kode pembersih, tetapi bukan SAM Kotlin, tipe fungsi adalah kelas pertama di Kotlin, jadi, SAM tidak memiliki arti untuk Kotlin, tipe fungsi dengan typealias lebih gaya Kotlin.
vg0x00
17

Solusi terbaik adalah dengan menggunakan typealias di tempat antarmuka Java Anda

typealias MyInterface = (Location) -> Unit

fun addLocationHandler(myInterface:MyInterface) {

}

Daftarkan seperti ini:

val myObject = { location -> ...}
addLocationHandler(myObject)

atau bahkan lebih bersih

addLocationHandler { location -> ...}

Aktifkan seperti ini:

myInterface.invoke(location)

3 opsi saat ini tampaknya:

  • typealias (berantakan ketika dipanggil dari java)
  • antarmuka kotlin (berantakan ketika dipanggil dari kotlin; Anda perlu membuat objek) Ini adalah langkah besar kembali IMO.
  • antarmuka java (kurang berantakan ketika dipanggil dari kotlin; lambda membutuhkan nama antarmuka yang diawali sehingga Anda tidak memerlukan objek; juga tidak dapat menggunakan lambda di luar fungsi kurung fungsi kurung)

Saat mengonversi pustaka kami ke Kotlin, kami sebenarnya meninggalkan semua antarmuka dalam kode Java, karena lebih bersih untuk memanggil Java dari Kotlin daripada Kotlin dari Kotlin.

Steven Spungin
sumber
8

Coba akses ke antarmuka Anda seperti ini:

 object : MyInterface {
    override fun onSomething() { ... }
}
Jéwôm '
sumber
6

jika Anda memiliki kelas Java seperti ini:

recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new RecyclerTouchListener.ClickListener()
        {
              //Your Code
        }));

Anda harus mengkonversi kode ini dari Jawa ke Kotlin seperti ini:

override fun showJozList (list : List<ResponseGetJuzList.Parameter4>) {
        adapter.addData(list)
        jozlist_recycler.addOnItemTouchListener(RecyclerTouchListener(
                activity ,
                jozlist_recycler ,
                object : RecyclerTouchListener.ClickListener
                    {
                          //Your Code
                    }))

convert Java Interface :

new RecyclerTouchListener.ClickListener()

untuk Gaya Antarmuka Kotlin :

object : RecyclerTouchListener.ClickListener
Adnan Abdollah Zaki
sumber
1

Jika antarmuka adalah untuk metode pendengar kelas, ubah definisi antarmuka ke tipe fungsi. Itu membuat kode lebih ringkas. Lihat yang berikut ini.

Kelas yang mengandung definisi pendengar

// A class
private var mLocationMeasuredListener = (location: Location) -> Unit = {}

var setOnLocationMeasuredListener(listener: (location: Location) -> Unit) {
    mLocationMeasuredListener = listener
}

// somewhere in A class
mLocationMeasuredListener(location)

Kelas lain

// B class
aClass.setOnLocationMeasuredListener { location ->
    // your code
}
Shin Seungwoo
sumber
-1
class YourClass : YourInterface {  
    override fun getTest() = "test"    
}

interface YourInterface {
    fun getTest(): String
}

val objectYourClass: YourInterface = YourClass()
print(objectYourClass.getTest())
Braian Coronel
sumber