如何更改此功能以摆脱冗余 SAM 构造函数?

How to change this function to get rid of Redundant SAM-constructior?

所以,我想让SetOnClickListener负责打开gallery。它有效,但是当我尝试将代码添加到 commitgithub 时,我不能,因为我使用了 Redundant SAM-Constructor。所以我的问题是,如何更改我的代码,使其在没有它的情况下也能正常工作?

class MainActivity : AppCompatActivity() {
private var dialogView: View? = null

private val getPreviewImage = registerForActivityResult(ActivityResultContracts.GetContent(), ActivityResultCallback {
    it?.let { uri ->
        dialogView?.findViewById<ImageView>(R.id.imageChange)?.setImageURI(it)
    }?:run {
        Log.e("MainActivity", "URI not present")
    }
})

private val getPreviewVideo = registerForActivityResult(ActivityResultContracts.GetContent(), ActivityResultCallback {
it?.let { uri ->
    dialogView?.findViewById<VideoView>(R.id.videoChange)?.setVideoURI(it)
}?: run{
    Log.e("MainActivity", "URI not present")
    }
})

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

    bottomNavigationView.background = null
    bottomNavigationView.menu.findItem(R.id.placeholder).isEnabled = false
    replaceFragment(HomeFragment())

    bottomNavigationView.setOnItemSelectedListener {
        when (it.itemId) {
            R.id.home -> replaceFragment(HomeFragment())
            R.id.player -> replaceFragment(PlayerFragment())
            R.id.profile -> replaceFragment(ProfileFragment())
            R.id.settings -> replaceFragment(SettingsFragment())
        }
        true
    }

    popupAddButton.setOnClickListener {
        showDialog()
    }
}

private fun replaceFragment(fragment: Fragment) {
    val transaction = supportFragmentManager.beginTransaction()
    transaction.replace(R.id.fragment_container, fragment)
    transaction.commit()
}
@SuppressLint("InflateParams")
private fun showDialog() { //this is for popupWindow
    dialogView = layoutInflater.inflate(R.layout.popup, null)
    val dialog = Dialog(this)
    val titleEditText = dialogView?.findViewById<EditText>(R.id.titleEdit) //popUp edit field title
    val descEditText = dialogView?.findViewById<EditText>(R.id.description) //popUp edit field description

    dialogView?.addImage?.setOnClickListener {
        getPreviewImage.launch("image/*")

    }
    dialogView?.addVideo?.setOnClickListener {
        getPreviewVideo.launch("video/*")
    }

    dialogView?.addButton?.setOnClickListener {
        AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
        if (titleEditText?.text?.isEmpty() == true || descEditText?.text?.isEmpty() == true){
            Toast.makeText(applicationContext, "add required data", Toast.LENGTH_SHORT).show()
        }else{
            Toast.makeText(applicationContext, "Added", Toast.LENGTH_SHORT).show()
        }
    }
    dialog.setContentView(dialogView!!)
    dialog.show()
   }
}

我猜你的意思是你试图推送到的 Git 回购的一些 lint 规则不允许冗余的 SAM 构造函数。

SAM 构造函数是指您使用 Kotlin 为功能接口提供的假“构造函数”。对于任何 Java 函数式接口 (SAM)(或 Kotlin fun 接口),Kotlin 创建一个看起来像构造函数的隐式内联函数。它使用该接口的名称作为函数名称,并采用与 SAM 签名匹配的功能引用参数。

例如,如果您在 Java

中定义此接口
public interface Foo {
    public int bar(String value);
}

或者如果您在 Kotlin 中将其定义为

fun interface Foo {
    fun bar(value: String): Int
}

Kotlin 隐式创建了这个函数。你无法在任何地方看到它,但你可以使用它。它只是内联的,所以不能在 Java 中或通过反射访问。

inline fun Foo(crossinline function: (value: String)->Int) = object: Foo {
    override fun bar(value: String): Int = function(value)
}

这个伪造的构造函数用于当你想创建该接口的实例以存储在 属性 中时。当您将 lambda 作为函数的最后一个参数传递时,您不需要使用此 SAM 构造函数,因为您可以直接传递 lambda 而无需调用此构造函数。 Kotlin 自动知道要从 lambda 构建什么接口。*

所以你的代码像

private val getPreviewImage = registerForActivityResult(ActivityResultContracts.GetContent(), ActivityResultCallback {
    it?.let { uri ->
        dialogView?.findViewById<ImageView>(R.id.imageChange)?.setImageURI(it)
    }?:run {
        Log.e("MainActivity", "URI not present")
    }
})

正在使用冗余 SAM 构造函数,可以替换为

private val getPreviewImage = registerForActivityResult(ActivityResultContracts.GetContent()) { 
    it?.let { uri ->
        dialogView?.findViewById<ImageView>(R.id.imageChange)?.setImageURI(it)
    }?:run {
        Log.e("MainActivity", "URI not present")
    }
}

您还为 val getPreviewVideo 使用了冗余 SAM 构造函数。

* 一个例外是当函数的重载将不同的接口作为最后一个参数时。然后你需要假构造函数来为构造函数区分它们。


旁注:像这样链接作用域函数是不好的做法 (?.let...?:run)。除了难以阅读之外,很容易不小心做一些会导致两个块都被执行的事情。例如,如果 URI 不为空但 dialogView 为空,则无论如何都会执行您的 run 块,因为 let 的计算结果为空。我会这样写:

private val getPreviewImage = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
    if (uri != null) {
        dialogView?.findViewById<ImageView>(R.id.imageChange)?.setImageURI(uri)
    } else {
        Log.e("MainActivity", "URI not present")
    }
}