如何更改此功能以摆脱冗余 SAM 构造函数?
How to change this function to get rid of Redundant SAM-constructior?
所以,我想让SetOnClickListener
负责打开gallery
。它有效,但是当我尝试将代码添加到 commit
到 github
时,我不能,因为我使用了 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")
}
}
所以,我想让SetOnClickListener
负责打开gallery
。它有效,但是当我尝试将代码添加到 commit
到 github
时,我不能,因为我使用了 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")
}
}