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

发布于 2025-01-10 04:17:29 字数 2935 浏览 3 评论 0原文

所以,我想制作 SetOnClickListener 来负责打开gallery。它可以工作,但是当我尝试将代码添加到 commitgithub 时,我不能这样做,因为我使用了冗余 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()
   }
}

So, i want to make SetOnClickListener that will be responsible for opening gallery. It works, but when i try to add code to commit to github i can't, because i used Redundant SAM-Constructor. So my question is, how to change my code, so it will work without it?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝天 2025-01-17 04:17:29

我猜你的意思是你尝试推送的 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")
    }
}

Youalsoused a Redundant SAM constructor for val getPreviewVideo.

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


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

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

I'm guessing that what you mean is that some lint rule for the Git repo you're trying to push to doesn't allow redundant SAM constructors.

A SAM constructor is when you use a fake "constructor" supplied by Kotlin for functional interfaces. For any Java functional interface (SAM) (or Kotlin fun interface), Kotlin creates an implicit inline function that looks like a constructor. It uses the name of that interface as the function name and takes a parameter of a functional reference matching the signature of the SAM.

So for example, if you define this interface in Java

public interface Foo {
    public int bar(String value);
}

or if you defined it in Kotlin as

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

Kotlin implicitly creates this function. You can't see it anywhere but you can use it. It's inline only so cannot be accessed in Java or by reflection.

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

This fake constructor is for when you want to create an instance of that interface to store in a property. You don't need to use this SAM constructor when you are passing a lambda as the last argument of a function, because you can just pass the lambda directly without calling this constructor. Kotlin automatically knows what interface to build out of the lambda.*

So your code like

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

is using a redundant SAM constructor and can be replaced with

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

You also used a redundant SAM constructor for val getPreviewVideo.

* An exception is when there are overloads of a function that take different interfaces as the last parameter. Then you would need the fake constructor to distinguish between them for the constructor.


Side note: it is bad practice to chain scope functions like that (?.let...?:run). Aside from being hard to read, it is very easy to accidentally do something that will cause both blocks to be executed. For example, if the URI is not null but dialogView is null, your run block will be executed anyway because let will evaluate to null. I would write it like this:

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")
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文