更改包含在 DialogFragment 内的 AlertDialog 中正/负按钮的名称

问题描述 投票:0回答:1

我有一个自定义

DialogFragment
ListWorkoutTypeDialog
,它会打开一个对话框,通过类内的
AlertDialog
删除或编辑我的健身应用程序的锻炼类型。 目标是能够根据用户是否删除了条目来更改此
AlertDialog 
上的正面和负面按钮的文本。
即。如果用户没有更改任何内容,它将显示一个标有“关闭”的负向按钮,否则如果有任何更改,它将显示一个正向“保存”按钮和一个负向“取消”按钮。目前我只是想将“关闭”按钮更改为“取消”,即使我也遇到了麻烦。

我在设置对

AlertDialog
的引用并在调用类(我的
MainActivity
)中获取该引用时遇到问题。它总是返回 null,即使我在调用获取引用之前
create()
show()
AlertDialog

我尝试在

ListWorkoutTypeDialog
类中设置按钮文本,但仍然导致空指针异常。

观察到

alertDialog
onCreateDialog
重写函数中设置,因此应该设置。然而,即使在这个函数被调用之后,我尝试使用
alertDialog
获取对
getAlertDialog
的引用,它仍然是
null

这是我的

ListWorkoutTypeDialog
课程:

package com.example.workoutbuddy.dialogs

import android.app.Activity
import android.app.AlertDialog
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.util.Log
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.lifecycleScope
import com.example.workoutbuddy.MainActivity
import com.example.workoutbuddy.R
import com.example.workoutbuddy.db.WorkoutType
import com.example.workoutbuddy.databinding.DialogWorkoutTypeListBinding
import com.example.workoutbuddy.util.findById
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

// display all workoutTypes in a list where user can long press to remove them or tap to edit them
// takes in a list of workoutTypes to display, activity context and a FragmentManager
class ListWorkoutTypeDialog(workoutTypes: MutableList<WorkoutType?>?, private var context: Activity, private var fm: FragmentManager) : DialogFragment() {

    // copy of workoutTypes
    private var realWorkoutTypesList = workoutTypes?.toMutableList()
    // true when we want to save (ie. save button clicked)
    private var save = false
    // list of workoutTypes to be displayed
    private var arrayOfWorkoutTypes = mutableListOf<String>();
    // adaptor for workoutTypes array
    private var adapter = ArrayAdapter(context, R.layout.blank_text_view_black_text, arrayOfWorkoutTypes)
    // tempMap for mapping position in list to primary ID keys of workoutTypes
    private var tempMap: MutableMap<Int, Int> = mutableMapOf<Int, Int>()
    // if firstRun
    private var firstRun = true
    // mutableList of IDs to be removed
    private var idsToRemove = mutableListOf<Int>()
    // reference to self (this)
    private var self = this

    private lateinit var alertDialog: AlertDialog



    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        return activity?.let {
            val builder = AlertDialog.Builder(it)

            val binding = DialogWorkoutTypeListBinding.inflate(layoutInflater)

            // clear the array of workoutTypes
            arrayOfWorkoutTypes.clear()
            // null check
            if (realWorkoutTypesList != null) {
                // for each workoutType (wt) add them to the array list to be displayed
                for (wt in realWorkoutTypesList!!) {
                    arrayOfWorkoutTypes.add("Workout ${wt!!.identifier} - ${wt.name}")
                }
            }


            // setup adaptor
            binding.workoutTypeList.adapter = adapter

            // on long click we delete the long clicked item
            binding.workoutTypeList.onItemLongClickListener = AdapterView.OnItemLongClickListener {
                    _,_,_,position ->
                // if position is 0 (placeholder no workout item) don't remove as it is the default
                if (position.toInt() != 0) {
                    // removes item from listview array
                    arrayOfWorkoutTypes.removeAt(position.toInt())

                    if (firstRun) {
                        // remove from lists
                        val num = findById(realWorkoutTypesList, (context as MainActivity).getWorkoutIDByPosition(position.toInt()))
                        realWorkoutTypesList?.remove(num)
                        idsToRemove.add((context as MainActivity).getWorkoutIDByPosition(position.toInt()))
                        firstRun = false
                    } else {
                        // tempMap now set so use that as positions will change as we remove items
                        idsToRemove.add(tempMap[position.toInt()]!!)
                        val num = findById(realWorkoutTypesList, tempMap[position.toInt()]!!)
                        realWorkoutTypesList?.remove(num)
                    }
                    // update the map as items are deleted
                    tempMap = (context as MainActivity).getSpinnerListMappings(realWorkoutTypesList)
                    // updates/recycles view
                    adapter.notifyDataSetChanged()
                }
                true
            }

            // on a short click we edit the item clicked
            binding.workoutTypeList.onItemClickListener = AdapterView.OnItemClickListener {
                _,_,_,position ->

                // make sure we don't remove the default workout "No workout" placeholder
                if (position.toInt() != 0) {
                    var tempWorkoutType: WorkoutType? = null
                    lifecycleScope.launch(Dispatchers.IO) {
                        val workoutTypeDAO = (context as MainActivity).db.getWorkoutTypeDao()

                        tempWorkoutType = workoutTypeDAO.get((context as MainActivity).getWorkoutIDByPosition(position.toInt()))

                        lifecycleScope.launch(Dispatchers.Main) {
                            // show the add/update workout dialog
                            val dialog = AddUpdateWorkoutTypeDialog(fm, tempWorkoutType, self)
                            dialog.show(fm, "WORKOUT_TYPE_UPDATE_DIALOG")
                        }
                    }
                }

            }

            // HERE I SET THE ALERTDIALOG
            alertDialog = builder.setView(binding.root)
                .setNegativeButton("Dismiss") { _, _ ->
                    // send cancel data
                    save = false
                    this.dismiss()
                }.create()

            Log.d("status", "alertDialog set")

            return builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")
    }

    fun getAlertDialog(): AlertDialog {
        // returns the AlertDialog used to make the alert
        return alertDialog
    }

    // refresh workout types
    fun refresh(wtl: MutableList<WorkoutType?>?) {
        arrayOfWorkoutTypes.clear()
        if (wtl != null) {
            for (wt in wtl) {
                arrayOfWorkoutTypes.add("Workout ${wt!!.identifier} - ${wt.name}")
            }
        }
        if (wtl != null) {
            realWorkoutTypesList = wtl.toMutableList()
        }
        // refresh/recycle view
        adapter.notifyDataSetChanged()
    }

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        val activity: Activity? = activity
        if (activity is DialogInterface.OnDismissListener) {
            // if save button clicked update list and remove deleted IDs
            if (save) {
                (activity as MainActivity).onWorkoutListUpdate(idsToRemove)
            }
        }
    }
}

这是我调用对话框的片段(在我的

MainActivity
中):

                    val workoutTypeDAO = db.getWorkoutTypeDao()

                    // spawn list dialog
                    val dialog = ListWorkoutTypeDialog(workoutTypeDAO.getAll()?.toMutableList(), self, supportFragmentManager)
                    // refresh the list
                    dialog.refresh(workoutTypeDAO.getAll()?.toMutableList())
                    // show the dialog
                    dialog.show(supportFragmentManager, "WORKOUT_LIST_VIEW")

                    Log.d("status", "changing button")
                    // set the button to cancel
                    dialog.getAlertDialog().getButton(AlertDialog.BUTTON_NEGATIVE).text = "Cancel" //ERROR happens here, getAlertDialog returns NULL


我收到以下错误:

alertDialog
未初始化,即使它在设置按钮之前运行:

2024-04-01 15:26:11.006 22922-22962 status                  com.example.workoutbuddy             D  changing button (this should be called last)
2024-04-01 15:26:11.025 22922-22962 AndroidRuntime          com.example.workoutbuddy             E  FATAL EXCEPTION: DefaultDispatcher-worker-1
                                                                                                    Process: com.example.workoutbuddy, PID: 22922
                                                                                                    kotlin.UninitializedPropertyAccessException: lateinit property alertDialog has not been initialized
                                                                                                        at com.example.workoutbuddy.dialogs.ListWorkoutTypeDialog.getAlertDialog(ListWorkoutTypeDialog.kt:133)
                                                                                                        at com.example.workoutbuddy.MainActivity$onOptionsItemSelected$1.invokeSuspend(MainActivity.kt:116)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
                                                                                                        at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115)
                                                                                                        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:100)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
                                                                                                        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
                                                                                                        Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@83d2b55, Dispatchers.IO]
2024-04-01 15:26:11.031 22922-22922 status                  com.example.workoutbuddy             D  alertDialog set (this should be called first)

我不确定这是否是解决这个问题的正确方法,因为我对 Android 开发还很陌生,但我认为这应该相对容易。谢谢您的帮助。

android kotlin android-alertdialog android-dialogfragment
1个回答
0
投票

首先,您调用

create
两次,这可能是一个错误:

// HERE I SET THE ALERTDIALOG
alertDialog = builder.setView(binding.root)
    .setNegativeButton("Dismiss") { _, _ ->
        // send cancel data
        save = false
        this.dismiss()
     }.create()         // <-- alertDialog set to this instance

Log.d("status", "alertDialog set")

return builder.create() // <-- New, different instance returned 

接下来,你对show的工作原理有一个误解:

我收到以下错误:alertDialog 未初始化,即使它在设置按钮之前运行:

对话框不会立即显示。它被添加到片段管理器事务队列中以便稍后执行(如下一帧)。

// This actually means "schedule the dialog to be shown soon"
dialog.show(supportFragmentManager, "WORKOUT_LIST_VIEW")

Log.d("status", "changing button")
// set the button to cancel

// Dialog will NOT have been initialized one line of execution later
dialog.getAlertDialog().getButton(AlertDialog.BUTTON_NEGATIVE).text = "Cancel" //ERROR happens here, getAlertDialog returns NULL

最后,真正做你想做的事:我过去所做的是在对话框完全初始化时更新 onStart() 中的按钮:

class ListWorkoutTypeDialog {
    override onStart() {
        alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE).text = "Cancel"
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.