【问题标题】:Why do button clicks happen twice in this app?为什么在这个应用程序中按钮点击会发生两次?
【发布时间】:2021-10-05 16:22:17
【问题描述】:

我有一个应用程序,其中一个功能是您可以通过单击它的卡片视图来选择一周中的哪一天。

我目前的问题是,如果你做下面的序列,你会得到一个意想不到的结果:

清除 -> 选择日期 -> 添加任务 -> 提交 -> 后退按钮到主活动

当您执行此序列时,数据库会在初始清除后意外再次清除,或者如果您去一天,添加任务并导航回来,它会再次运行和/或让您回到视图中你刚离开的那天。

我注意到的和我尝试过的:

我拥有的foreach 循环完成了它应该做的事情:翻阅工作日,直到找到正确的那个......但是它又做了一次?我知道从日志中发生的事情太多了,并且在完成后再次弹出Toast(它说 db 已清除 自动随后 没有什么可清除)。我也尝试在 foreach 循环中添加断点,但我认为这对我没有帮助,因为如果我没记错的话,它只会中断循环的迭代一次?

我尝试了一个活动级别布尔变量,让它在我需要时停止和启动,但问题是我要么需要按任何给定的卡两次,在第一次之后它什么都不做项目被选中,或者问题仍然存在。

我已经在 xml 中为按钮侦听器使用了 onClick,但我也尝试将它编程到活动 kotlin 类中,但没有任何区别

也许我只是在某处错过了循环的额外迭代,或者在适当的地方中断了?

主要活动 XML

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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" >

    <TextView
        android:id="@+id/top_box"
        android:layout_width="0dp"
        android:layout_height="90dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/clear_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@id/top_box"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/sunday_card"
        app:layout_constraintBottom_toTopOf="@id/wednesday_card">

        <TextView
            android:id="@+id/clear_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"
            />

    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/sunday_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@+id/top_box"
        app:layout_constraintLeft_toRightOf="@id/clear_card"
        app:layout_constraintRight_toLeftOf="@id/monday_card"
        app:layout_constraintBottom_toTopOf="@id/thursday_card">

        <TextView
            android:id="@+id/sunday_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"/>

    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/monday_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@id/top_box"
        app:layout_constraintLeft_toRightOf="@id/sunday_card"
        app:layout_constraintRight_toLeftOf="@id/tuesday_card"
        app:layout_constraintBottom_toTopOf="@id/friday_card">

        <TextView
            android:id="@+id/monday_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"/>

    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/tuesday_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@id/top_box"
        app:layout_constraintLeft_toRightOf="@id/monday_card"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@id/saturday_card">

        <TextView
            android:id="@+id/tuesday_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"/>

    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/wednesday_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@id/clear_card"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@id/thursday_card"
        app:layout_constraintBottom_toTopOf="@id/bottom_box">

        <TextView
            android:id="@+id/wednesday_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"/>

    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/thursday_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@id/sunday_card"
        app:layout_constraintLeft_toRightOf="@id/wednesday_card"
        app:layout_constraintRight_toRightOf="@id/friday_card"
        app:layout_constraintBottom_toTopOf="@id/bottom_box">

        <TextView
            android:id="@+id/thursday_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"/>

    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/friday_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@id/monday_card"
        app:layout_constraintLeft_toRightOf="@id/thursday_card"
        app:layout_constraintRight_toLeftOf="@id/saturday_card"
        app:layout_constraintBottom_toTopOf="@id/bottom_box">

        <TextView
            android:id="@+id/friday_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"/>

    </com.google.android.material.card.MaterialCardView>

    <com.google.android.material.card.MaterialCardView
        android:id="@+id/saturday_card"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:onClick="buttonClick"
        app:layout_constraintTop_toBottomOf="@id/tuesday_card"
        app:layout_constraintLeft_toRightOf="@id/friday_card"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toTopOf="@id/bottom_box">

        <TextView
            android:id="@+id/saturday_card_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:textSize="20sp"
            android:gravity="center"/>

    </com.google.android.material.card.MaterialCardView>

    <TextView
        android:id="@+id/bottom_box"
        android:layout_width="0dp"
        android:layout_height="90dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val plannerViewModel: PlannerViewModel by viewModels {
        PlannerViewModelFactory((application as PlannerApplication).repository)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val clearButtonText = binding.clearCardText
        val sundayButtonText = binding.sundayCardText
        val mondayButtonText = binding.mondayCardText
        val tuesdayButtonText = binding.tuesdayCardText
        val wednesdayButtonText = binding.wednesdayCardText
        val thursdayButtonText = binding.thursdayCardText
        val fridayButtonText = binding.fridayCardText
        val saturdayButtonText = binding.saturdayCardText

        // Setting day card names
        clearButtonText.text = "Clear"
        sundayButtonText.text = "Sun"
        mondayButtonText.text = "Mon"
        tuesdayButtonText.text = "Tue"
        wednesdayButtonText.text = "Wed"
        thursdayButtonText.text = "Thu"
        fridayButtonText.text = "Fri"
        saturdayButtonText.text = "Sat"
        sundayButtonText.text = "Sun"
    }

    private fun startWeekdayActivity(day: Weekday) {
        val intent = Intent(this, WeekdayActivity::class.java)
        intent.putExtra("dayId", day.id)
        this.startActivity(intent)
    }

    private fun clearDb() {
        val alertDialog: AlertDialog? = this?.let { outerIt ->
            val builder = AlertDialog.Builder(outerIt)
            builder.apply {
                setPositiveButton("Clear",
                        DialogInterface.OnClickListener { dialog, id ->

                            plannerViewModel.allTasks.observe(outerIt, {
                                if (it.count() == 0) {
                                    Toast.makeText(context, "No tasks to clear", Toast.LENGTH_SHORT).show()
                                }
                                else {
                                    plannerViewModel.deleteAllTasks()
                                    Toast.makeText(context, "Tasks cleared", Toast.LENGTH_SHORT).show()
                                }
                            })
                            })
                setNegativeButton("Cancel",
                        DialogInterface.OnClickListener { dialog, id ->
                            // User cancelled the dialog
                        })
            }
                    .setTitle("Clear tasks?")
                    .setMessage("Are you sure you want to clear the weeks tasks?")

            // Create the AlertDialog
            builder.create()
        }

                alertDialog?.show()
    }

    private fun checkDay(dayIn: String) {
        var dayOut: Weekday? = null
        plannerViewModel.allWeekdays.observe(this, { weekdays ->
            weekdays?.let {
                weekdays.forEach {
                        if (dayIn == "clear_card" && it.day == "Clear") {
                                clearDb()
                                dayOut = it
                        }
                    else {
                        val dayInAbr = dayIn.substring(0, 3).toLowerCase(Locale.ROOT)
                        val dayOutAbr = it.day.substring(0,3).toLowerCase(Locale.ROOT)

                        if (dayInAbr == dayOutAbr) {
                            dayOut = it
                            dayOut?.let { startWeekdayActivity(it) }
                        }
                    }

                    if (dayOut != null) {
                        return@let
                    }
                }
            }
        })
    }

    fun buttonClick(view: View) {
        when(view.id) {
            R.id.clear_card -> checkDay(view.context.resources.getResourceEntryName(R.id.clear_card).toString())
            R.id.sunday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.sunday_card).toString())
            R.id.monday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.monday_card).toString())
            R.id.tuesday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.tuesday_card).toString())
            R.id.wednesday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.wednesday_card).toString())
            R.id.thursday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.thursday_card).toString())
            R.id.friday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.friday_card).toString())
            R.id.saturday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.saturday_card).toString())
        }
    }
}

【问题讨论】:

  • 请在问题中添加您的PlannerViewModel
  • 在调用checkDay() 方法的每个点击事件上观察plannerViewModel.allWeekdays 是完全错误的。它是一个观察者;对于一个生命周期,您只需注册一次,而不是每次点击事件。在 onCreate() 方法中移动观察者,并仅在 plannerViewModel.allWeekdays 被任何其他事件更新时使用它。 plannerViewModel.allTasks 也是如此——您不需要在那里观察它,而只需使用 MutableLiveData#g​​etValue() 获取计数。
  • @Jay 这实际上解决了我的问题!我猜每次都给观察者打电话只是给很多观察者创造了条件?我将发布工作代码并接受答案。谢谢!

标签: android android-studio kotlin android-activity


【解决方案1】:

Jay 在 cmets 中回答的问题

如果您知道我可以将 SO 积分和声誉归功于他们的方法,请告诉我!

每次checkDay() 运行时,我都需要停止调用更多的观察者实例。将观察者移动到 onCreate() 以便它们只运行一次似乎解决了我的问题!

主要活动的工作代码

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val plannerViewModel: PlannerViewModel by viewModels {
        PlannerViewModelFactory((application as PlannerApplication).repository)
    }

    lateinit var weekdayList: List<Weekday>
    lateinit var taskList: List<Task>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val clearButtonText = binding.clearCardText
        val sundayButtonText = binding.sundayCardText
        val mondayButtonText = binding.mondayCardText
        val tuesdayButtonText = binding.tuesdayCardText
        val wednesdayButtonText = binding.wednesdayCardText
        val thursdayButtonText = binding.thursdayCardText
        val fridayButtonText = binding.fridayCardText
        val saturdayButtonText = binding.saturdayCardText

        // Setting day card names
        clearButtonText.text = "Clear"
        sundayButtonText.text = "Sun"
        mondayButtonText.text = "Mon"
        tuesdayButtonText.text = "Tue"
        wednesdayButtonText.text = "Wed"
        thursdayButtonText.text = "Thu"
        fridayButtonText.text = "Fri"
        saturdayButtonText.text = "Sat"
        sundayButtonText.text = "Sun"

        plannerViewModel.allTasks.observe(this, {
            taskList = it
        })

        plannerViewModel.allWeekdays.observe(this, {
            weekdayList = it
        })
    }

    private fun startWeekdayActivity(day: Weekday) {
        val intent = Intent(this, WeekdayActivity::class.java)
        intent.putExtra("dayId", day.id)
        this.startActivity(intent)
    }

    private fun clearDb(taskList: List<Task>) {
        val alertDialog: AlertDialog? = this?.let { outerIt ->
            val builder = AlertDialog.Builder(outerIt)
            builder.apply {
                setPositiveButton("Clear",
                        DialogInterface.OnClickListener { dialog, id ->
                            if (taskList.count() == 0) {
                                Toast.makeText(context, "No tasks to clear", Toast.LENGTH_SHORT).show()
                            } else {
                                plannerViewModel.deleteAllTasks()
                                Toast.makeText(context, "Tasks cleared", Toast.LENGTH_SHORT).show()
                            }
                        })
                setNegativeButton("Cancel",
                        DialogInterface.OnClickListener { dialog, id ->
                            // User cancelled the dialog
                        })
            }
                    .setTitle("Clear tasks?")
                    .setMessage("Are you sure you want to clear the weeks tasks?")

            builder.create()
        }

        alertDialog?.show()
    }

    private fun checkDay(dayIn: String, weekdayList: List<Weekday>) {
        weekdayList.forEach {
            if (dayIn == "clear_card" && it.day == "Clear") {
                clearDb(taskList)
            } else {
                val dayInAbr = dayIn.substring(0, 3).toLowerCase(Locale.ROOT)
                val dayOutAbr = it.day.substring(0, 3).toLowerCase(Locale.ROOT)

                if (dayInAbr == dayOutAbr) {
                    startWeekdayActivity(it)
                }
            }
        }
    }

    fun buttonClick(view: View) {
        when (view.id) {
            R.id.clear_card -> checkDay(view.context.resources.getResourceEntryName(R.id.clear_card).toString(), weekdayList)
            R.id.sunday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.sunday_card).toString(), weekdayList)
            R.id.monday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.monday_card).toString(), weekdayList)
            R.id.tuesday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.tuesday_card).toString(), weekdayList)
            R.id.wednesday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.wednesday_card).toString(), weekdayList)
            R.id.thursday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.thursday_card).toString(), weekdayList)
            R.id.friday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.friday_card).toString(), weekdayList)
            R.id.saturday_card -> checkDay(view.context.resources.getResourceEntryName(R.id.saturday_card).toString(), weekdayList)
        }
    }
}

【讨论】:

    猜你喜欢
    • 2018-12-23
    • 2021-12-16
    • 2011-06-02
    • 2018-03-05
    • 2010-09-07
    • 2015-06-27
    • 2011-02-21
    • 2020-06-12
    相关资源
    最近更新 更多