“Không đủ thông tin để suy ra tham số T” với Kotlin và Android


110

Tôi đang cố gắng sao chép ListView sau trong ứng dụng Android của mình bằng Kotlin: https://github.com/bidrohi/KotlinListView .

Rất tiếc, tôi đang gặp một lỗi mà tôi không thể tự khắc phục. Đây là mã của tôi:

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
    }
}
}

Bố cục chính xác như ở đây: https://github.com/bidrohi/KotlinListView/tree/master/app/src/main/res/layout

Thông báo lỗi đầy đủ mà tôi nhận được là sau: Lỗi: (92, 31) Loại suy luận không thành công: Không đủ thông tin để suy ra tham số T trong fun findViewById (p0: Int): T! Hãy chỉ định nó một cách rõ ràng.

Tôi đánh giá cao bất kỳ sự giúp đỡ nào mà tôi có thể nhận được.


2
Bạn có thể thử thay đổi this.label = ... as TextViewđể this.label = row?.findViewById<TextView>và làm như vậy Tương tự cho val listView = ...? Vui lòng cho tôi biết nếu điều này hoạt động để tôi có thể đưa ra câu trả lời thích hợp trong trường hợp đó.
Christian Brüggemann

1
Dòng nào gây ra lỗi?
voddan

Bạn có thể chứng minh vấn đề bằng một ví dụ nhỏ hơn không?
voddan

@ ChristianBrüggemann Như thế này: i.imgur.com/ZeWKjt5.png và điều này: i.imgur.com/Can7w0p.png ? Với sửa đổi của bạn hiện nay có các lỗi này: i.imgur.com/qqPAjrL.png
Timo Güntner

1
Hãy thử this.label = row? .FindViewById <TextView> (R.id.label) as TextView
Alf Moh

Câu trả lời:


224

Bạn phải đang sử dụng API cấp 26 (trở lên). Phiên bản này đã thay đổi chữ ký của View.findViewById()- xem tại đây https://developer.android.com/about/versions/oreo/android-8.0-changes#fvbi-signature

Vì vậy, trong trường hợp của bạn, khi kết quả findViewByIdlà không rõ ràng, bạn cần cung cấp loại:

1 / Thay đổi

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

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

2 / Thay đổi

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

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

Lưu ý rằng trong 2 / cast chỉ được yêu cầu vì rowlà nullable. Nếu label là nullable quá, hoặc nếu bạn rowkhông nullable, nó sẽ không được yêu cầu.


10
Đây là cách giải quyết hàng loạt vấn đề này: Mở hộp thoại Thay thế trong Đường dẫn (Ctrl + Shift + R) và chọn hộp regex. Thay thế findViewById\((.+?)\)\s+as\s+(.+)bằng findViewById<$2>\($1\)và chạy thay thế trên tất cả các tệp. Nó đã giải quyết gần như tất cả các lỗi của tôi.
Gustav Karlsson

1
Tại sao trong Java suy ra kiểu View theo mặc định là đủ và không đủ trong Kotlin? findViewById(R.id.tabLayout).setOnClickListener(v-> Log.d(TAG, "login: "));điều này là tốt cho Java.
Serge

findViewById\((.+?)\)\s+as\s+([A-Za-z0-9?]+)hoạt động tốt hơn cho tôi. Nó ngăn không cho một số mã dòng không quá @GustavKarlsson
user3680200 24/02/19

1
Liên kết không nói điều đó.
Alston

7

Andoid O thay đổi api findViewById từ

public View findViewById (int id);

đến

công khai cuối cùng T findViewById (int id)

vì vậy, nếu bạn nhắm mục tiêu đến API 26, bạn có thể thay đổi

val listView = findViewById (R.id.list) dưới dạng ListView

đến

val listView = findViewById (R.id.list)

hoặc là

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


4

Hoạt động của nó

API cấp 25 trở xuống sử dụng cái này

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

API cấp 26 trở lên sử dụng cái này

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

Chúc bạn mã hóa vui vẻ!


2

Thay đổi mã của bạn thành này. Nơi các thay đổi chính xảy ra được đánh dấu bằng dấu hoa thị.

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 }**
    }
}

Nếu bạn đang nhắm mục tiêu API 26 trong Ứng dụng của mình, thì câu trả lời dưới đây là câu trả lời chính xác. val listView = findViewById<ListView>(R.id.list)
EricWasTaken

@ericWasTaken Yeah, bạn nói đúng. Trình biên dịch phải suy ra kiểu từ nội dung trong dấu ngoặc. Đôi khi nó không thành công ở đó. Mã của bạn cũng chính xác. Sẽ cập nhật câu trả lời của tôi để phản ánh những thay đổi.
Alf Moh

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.