Kotlin 및 Android에서 "매개 변수 T를 추론하기에 정보가 충분하지 않음"


110

Kotlin을 사용하여 Android 앱에서 다음 ListView를 복제하려고합니다. https://github.com/bidrohi/KotlinListView .

불행히도 스스로 해결할 수없는 오류가 발생합니다. 내 코드는 다음과 같습니다.

MainActivity.kt:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val listView = findViewById(R.id.list) as ListView
    listView.adapter = ListExampleAdapter(this)
}

private class ListExampleAdapter(context: Context) : BaseAdapter() {
    internal var sList = arrayOf("Eins", "Zwei", "Drei")
    private  val mInflator: LayoutInflater

    init {
        this.mInflator = LayoutInflater.from(context)
    }

    override fun getCount(): Int {
        return sList.size
    }

    override fun getItem(position: Int): Any {
        return sList[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
        val view: View?
        val vh: ListRowHolder

        if(convertView == null) {
            view = this.mInflator.inflate(R.layout.list_row, parent, false)
            vh = ListRowHolder(view)
            view.tag = vh
        } else {
            view = convertView
            vh = view.tag as ListRowHolder
        }

        vh.label.text = sList[position]
        return view
    }
}

private class ListRowHolder(row: View?) {
    public val label: TextView

    init {
        this.label = row?.findViewById(R.id.label) as TextView
    }
}
}

레이아웃은 https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout 과 정확히 같습니다.

내가 얻는 전체 오류 메시지는 다음과 같습니다. 오류 : (92, 31) 유형 추론 실패 : 재미있는 매개 변수 T를 추론 할 정보가 충분하지 않습니다. findViewById (p0 : Int) : T! 명시 적으로 지정하십시오.

도움을 주시면 감사하겠습니다.


2
당신은 변화 시도 할 수 this.label = ... as TextViewthis.label = row?.findViewById<TextView>및 위해 이렇게 유사 할 val listView = ...? 이 경우 적절한 답변을 할 수 있도록 이것이 작동하는지 알려주십시오.
기독교 Brüggemann

1
오류를 일으키는 줄은 무엇입니까?
voddan

더 작은 예제로 문제를 설명 할 수 있습니까?
voddan

@ ChristianBrüggemann 이렇게 : i.imgur.com/ZeWKjt5.png 그리고 이것 : i.imgur.com/Can7w0p.png ? 편집으로 이러한 오류는 이제이 있습니다 : i.imgur.com/qqPAjrL.png
티모 Güntner

1
이 this.label = 로우 사용해 .findViewById <텍스트 뷰>와 같은 텍스트 뷰 (R.id.label)?
알프 모스

답변:


224

API 레벨 26 (또는 그 이상)을 사용해야합니다. 이 버전은 서명을 변경했습니다 View.findViewById()-여기를 참조하십시오 https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

따라서 결과 findViewById가 모호한 경우 유형을 제공해야합니다.

1 / 변경

val listView = findViewById(R.id.list) as ListView

val listView = findViewById<ListView>(R.id.list)

2 / 변경

this.label = row?.findViewById(R.id.label) as TextView

this.label = row?.findViewById<TextView>(R.id.label) as TextView

2 /에서는 캐스트 row가 nullable 이므로 캐스트 만 필요합니다 . 만약이 label 너무 Null을 허용했다, 또는 당신이 만든 경우 rowNull을 허용하지, 그것은 필요하지 않을 것입니다.


10
일괄 해결 방법은 다음과 같습니다. 경로 에서 바꾸기 대화 상자 (Ctrl + Shift + R)를 열고 정규식 상자를 선택합니다. 교체 findViewById\((.+?)\)\s+as\s+(.+)findViewById<$2>\($1\)하고, 모든 파일에 대체 실행합니다. 거의 모든 오류를 해결했습니다.
Gustav Karlsson

1
Java에서는 기본적으로 View 유형을 추론하기에 충분하고 Kotlin에서는 충분하지 않은 이유는 무엇입니까? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));이것은 Java에서는 괜찮습니다.
Serge

findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)나를 위해 더 잘 작동합니다. @GustavKarlsson
user3680200

1
링크는 그렇게 말하지 않습니다.
Alston

7

Andoid O 변경 findViewById API

public View findViewById (int id);

공개 최종 T findViewById (int id)

따라서 API 26을 대상으로하는 경우

val listView = findViewById (R.id.list) as ListView

val listView = findViewById (R.id.list)

또는

val listView : ListView = findViewById (R.id.list)


4

작동

API 레벨 25 이하에서 사용

    var et_user_name = findViewById(R.id.et_user_name) as EditText

API 레벨 26 이상 사용

    val et_user_name: EditText = findViewById(R.id.et_user_name)

행복한 코딩!


2

코드를 이것으로 변경하십시오. 주요 변경 사항이 발생한 위치는 별표로 표시됩니다.

package com.phenakit.tg.phenakit

import android.content.Context
import android.os.Bundle
import android.support.design.widget.BottomNavigationView
import android.support.v7.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import android.widget.TextView

public class MainActivity : AppCompatActivity() {

    private var mTextMessage: TextView? = null

    private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
        when (item.itemId) {
            R.id.navigation_home -> {
                mTextMessage!!.setText(R.string.title_home)
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_dashboard -> {
                mTextMessage!!.setText(R.string.title_dashboard)
                return@OnNavigationItemSelectedListener true
            }
            R.id.navigation_notifications -> {
                setContentView(R.layout.activity_list_view)
                return@OnNavigationItemSelectedListener true
            }
        }
        false
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mTextMessage = findViewById(R.id.message) as TextView?
        val navigation = findViewById(R.id.navigation) as BottomNavigationView
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)


        **val listView = findViewById<ListView>(R.id.list)**



        **listView?.adapter = ListExampleAdapter(this)**
    }

    private class ListExampleAdapter(context: Context) : BaseAdapter() {
        internal var sList = arrayOf("Eins", "Zwei", "Drei")
        private  val mInflator: LayoutInflater

        init {
            this.mInflator = LayoutInflater.from(context)
        }

        override fun getCount(): Int {
            return sList.size
        }

        override fun getItem(position: Int): Any {
            return sList[position]
        }

        override fun getItemId(position: Int): Long {
            return position.toLong()
        }

        override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
            val view: View?
            val vh: ListRowHolder

            if(convertView == null) {
                view = this.mInflator.inflate(R.layout.list_row, parent, false)
                vh = ListRowHolder(view)
                view.tag = vh
            } else {
                view = convertView
                vh = view.tag as ListRowHolder
            }

            vh.label.text = sList[position]
            return view
        }
    }

    private class ListRowHolder(row: View?) {
        public var label: TextView

        **init { this.label = row?.findViewById<TextView?>(R.id.label) as TextView }**
    }
}

앱에서 API 26을 대상으로하는 경우 아래 답변이 정답입니다. val listView = findViewById<ListView>(R.id.list)
EricWasTaken

@ericWasTaken 네, 맞아요. 컴파일러는 괄호 안의 내용에서 유형을 유추해야합니다. 때때로 그것은 실패합니다. 귀하의 코드도 정확합니다. 변경 사항을 반영하여 내 답변을 업데이트합니다.
Alf Moh

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.