【问题标题】:Kotlin OnClick ListenerKotlin OnClick 监听器
【发布时间】:2018-06-15 10:52:39
【问题描述】:

我正在尝试从 MainActivity 中定义的 UI 获取 Toast,并在 Base Activity 中为 onClick 侦听器编写代码。根据要求,我已将我的基类定义为开放的,但我仍然没有得到 Toast

这里是代码

基础活动

    open class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val buttonClick= findViewById<Button>(R.id.button)
        buttonClick?.setOnClickListener {
            Toast.makeText(this@BaseActivity, "Click...", Toast.LENGTH_LONG).show()
        }

    }
}

主活动

    class MainActivity : BaseActivity() {

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

activity_main.xml

 <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    tools:layout_editor_absoluteY="81dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="18dp"
        android:layout_marginBottom="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:text="Hello World!"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.409" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="190dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />


</android.support.constraint.ConstraintLayout>

你能告诉我代码有什么问题吗?我怎样才能从中获得点击

【问题讨论】:

  • 你忘记给setContentView打电话了吗?

标签: android kotlin


【解决方案1】:

我认为这里的问题是你在BaseActivity.onCreate 中调用val buttonClick= findViewById&lt;Button&gt;(R.id.button),它在MainActivity.onCreate 中调用之前你调用setContentView...所以视图是' t 尚未初始化,您还没有订阅点击事件。

您可以在MainActivity 中附加onClickListener,或者如果您仍想从您的BaseActivity 中执行此操作,您可以创建额外的initViews 方法并在setContentView 之后调用它:

class MainActivity : BaseActivity() {

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

        initViews()
    }
}



open class BaseActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    } 

    protected fun initViews() {
        val buttonClick= findViewById<Button>(R.id.button)
        buttonClick?.setOnClickListener {
            Toast.makeText(this@BaseActivity, "Click...", Toast.LENGTH_LONG).show()
        }
    }    
}

【讨论】:

  • 就个人而言,我认为这是一个不好的方法。您很有可能在某个时候忘记致电initViews,但没有任何效果,从而导致您进行数小时的调查。此外,如果您想解决这个问题并将initViews 定义为抽象,那么首先将其放在单独的方法中是没有意义的:只需将变量抽象。更多详情见我的回答
  • 虽然这不是最好的方法,但它不会强制你使用initViews,而拥有abstract val button 将强制每个扩展BaseActivity 的活动来实现它。此外,您的问题并没有解决核心问题。
  • 等一下,问题本身的意思是,他想要一个基本活动,它封装了一些逻辑(从那个活动扩展的每个活动都应该具有相同的逻辑),因此“强制每个活动”是正是他想要的
【解决方案2】:

您需要将监听器的代码移动到您的MainActivity

MainActivity.kt

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

            val buttonClick= findViewById<Button>(R.id.button)
            buttonClick?.setOnClickListener {
                Toast.makeText(this@MainActivity, "Click...", Toast.LENGTH_LONG).show()
            }

    }

因为您是在 BaseActivity 的 onCreate 中定义您的侦听器,所以您的 findViewById&lt;Button&gt;(R.id.button) 实际上是 null,因为 setContentView(R.layout.activity_main) 是在之后调用的。

【讨论】:

  • 它确实解决了这个问题,但它不符合他想要维护的逻辑:从 base one 继承的所有活动都应该以相同的方式运行
  • @GeorgySavatkov 是的,这是正确的,虽然你已经回答了,我会把功劳留给你的 :)
【解决方案3】:

在您的代码中,setContentView 仅在您尝试将侦听器设置为不存在的视图后调用。

一种可能的解决方案是仅在调用尝试设置内容视图的抽象方法后尝试添加点击侦听器(不带 ?.)。

abstract class BaseActivity: AppCompatActivity() {
    abstract val layoutId: Int

    override fun onCreate(bundle: Bundle?) {
         super.onCreate(bundle)
         setContentView(layoutId) 
         button.setOnClickListener {
            ... 

【讨论】:

    【解决方案4】:

    问题是您试图访问 BaseActivity 类中的按钮,而您的布局仅在 MainActivity 内加载。因此无法找到该按钮。解决方案是:

    abstract class BaseActivity : AppCompatActivity() {
    
       abstract val buttonClick: Button
    
       override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
           buttonClick.setOnClickListener {
               Toast.makeText(this@BaseActivity, "Click...", Toast.LENGTH_LONG).show()
        }
      }
    }
    
    class MainActivity : BaseActivity() {
       override val buttonClick: Button
            get() = button // Kotlin view binding
    
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           setContentView(R.layout.activity_main)
       }
    }
    

    已完成的工作:我们定义了一个抽象按钮并为其分配了一个点击监听器。因此,点击处理的逻辑留在了基础活动中,而 MainActivity 只是定义了一个视图(R.id.button,通过 kotlin 视图绑定)来操作。

    【讨论】:

    • 等我注意到这里有一个小问题 > BaseActivity.onCreate() 将在 MainActivity.onCreate() 之前被首先调用,这仍然会使 buttonClick 为空。
    【解决方案5】:

    使用它 Toast.makeText(getApplicationContext(), "Click " , Toast.LENGTH_LONG).show();

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-16
      • 2019-05-27
      • 2019-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-30
      相关资源
      最近更新 更多