带有 AlertDialog returns EditText 的自定义 DialogFragment 作为“”

Custom DialogFragment with AlertDialog returns EditText as ""

我有一个自定义 DialogFragment,我用它来捕获我将用来创建数据库条目的用户输入。我在 AlertDialog 中使用 EditText。我正在尝试为我的应用程序使用单个 activity,而我正在学习的原始教程使用了多个活动和意图,但在大多数情况下这似乎已经过时了。

当我调试时,我发现 EditText 正在返回“”,并且在我调用 TextUtils.isEmpty()[= 时显示为空39=] 在 MainActivity onDialogPositiveClick.

我已经对这里的表格做了很多梳理,但我很困惑:

1) 我找到的许多答案都在 Java 而不是 Kotlin

2) 许多人提到了 onCreate 但没有指定 onCreateView 与 onCreateDialog 或者是否只有我需要覆盖的 onCreate。

我对此进行了研究并找到了让我对何时以及是否需要扩充布局感到困惑的答案。当前的迭代我根本没有夸大它。我只是在 AlertDialog 构建器中设置它。

可能是我不理解的界面。我应该如何在对话框和 MainActivity 之间传递信息?界面似乎通过了对话框本身,但在从对话框中获取 EditText 时我似乎遗漏了一些东西。

我的自定义 DialogFragment

class NewSongFragment : DialogFragment() {
    lateinit var listener: NewSongListener

    lateinit var editNewSong: EditText
    lateinit var editBPM: EditText

    interface NewSongListener {
        fun onDialogPositiveClick(dialog: DialogFragment)
        fun onDialogNegativeClick(dialog: DialogFragment)
    }

    /** The system calls this to get the DialogFragment's layout, regardless
    of whether it's being displayed as a dialog or an embedded fragment. */
   /*
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Inflate the layout to use as dialog or embedded fragment
        return inflater.inflate(R.layout.fragment_new_song, container, false)

    }
*/
    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
    override fun onAttach(context: Context) {
        super.onAttach(context)
        // Verify that the host activity implements the callback interface
        try {
            // Instantiate the NoticeDialogListener so we can send events to the host
            listener = context as NewSongListener
        } catch (e: ClassCastException) {
            // The activity doesn't implement the interface, throw exception
            throw ClassCastException((context.toString() +
                    " must implement NewSongListener"))
        }
    }



    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {

        return activity?.let {
            // Use the Builder class for convenient dialog construction
            val builder = AlertDialog.Builder(it)

            //add inflater
            //val inflater = requireActivity().layoutInflater;
            //val view = inflater.inflate(R.layout.fragment_new_song, null)
            builder
                .setView(R.layout.fragment_new_song)
                .setCancelable(true)
                .setNegativeButton(R.string.cancel,DialogInterface.OnClickListener { dialog, id ->
                    dialog?.cancel()
                })
                .setPositiveButton(R.string.button_save,
                    DialogInterface.OnClickListener {dialog, _ ->
                        listener.onDialogPositiveClick(this)
                    })

            // Create the AlertDialog object and return it
            builder.create()
        } ?: throw IllegalStateException("Activity cannot be null")

    }

}

我的 MainActivity

class MainActivity : AppCompatActivity(),NewSongFragment.NewSongListener {
    private val songViewModel: SongViewModel by viewModels {
        SongViewModelFactory((application as SongApplication).repository)
    }

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

        //create view
        val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
        val adapter = ItemAdapter(this,
            ItemAdapter.OnClickListener { rating -> songViewModel.insertRating(rating) }
        )
        recyclerView.adapter = adapter
        recyclerView.layoutManager = LinearLayoutManager(this)

        //initialize data
        songViewModel.allSongs.observe(this) { song ->
            // Update the cached copy of the songs in the adapter.
            song.let { adapter.submitList(it) }
        }


        // Use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView

        recyclerView.setHasFixedSize(true)

        //add song button
        val fab = findViewById<FloatingActionButton>(R.id.fab)
        fab.setOnClickListener {
            showNewSongDialog()
            }
        }

    private fun showNewSongDialog() {
        // Create an instance of the dialog fragment and show it
        val dialog = NewSongFragment()
        dialog.show(supportFragmentManager, "NewSongFragment")
    }
    override fun onDialogPositiveClick(dialog: DialogFragment) {
        // User touched the dialog's positive button
        val editNewSong = dialog.view?.findViewById<EditText>(R.id.newSongTitle)
        val editBPM = dialog.view?.findViewById<EditText>(R.id.newSongBpm)
        if(TextUtils.isEmpty(editNewSong?.text)){

        }else{
            val newSong = Song(editNewSong?.text.toString(),100)
            songViewModel.insertSong(newSong)
            val rating = Rating(System.currentTimeMillis(),newSong.songTitle, 50)
            songViewModel.insertRating(rating)
        }

    }

    override fun onDialogNegativeClick(dialog: DialogFragment) {
        // User touched the dialog's negative button
    }


}

因为您将对话框添加为 Fragment,您应该使用 onCreateView 来扩充视图,而不是尝试在 onCreateDialog 中添加视图。

您正在添加带有资源标识符的布局,因此您获取视图的调用返回空值。 (为什么?视图在内部膨胀,只是处理方式不同。)由于您正在使用 AlertDialog 来收集数据,因此您必须添加一个膨胀视图。

我还建议您更改界面以隐藏对话框的详细信息;没有理由让主要activity知道对话框的内部结构。它只需要歌曲名称和 BPM 以及其他一些东西。您会发现代码更容易理解和维护。

此处稍作修改。此代码仅捕获歌曲标题,但可以轻松扩展以包含其他数据。

NewSongFragment中:

interface NewSongListener {
    fun onDialogPositiveClick(songTitle: String)
    fun onDialogNegativeClick(dialog: DialogFragment)
}

val inflater = requireActivity().layoutInflater;
val view = inflater.inflate(R.layout.fragment_new_song, null)
builder
    .setView(view)
    .setCancelable(true)
    .setNegativeButton(R.string.cancel, DialogInterface.OnClickListener { dialog, id ->
        dialog?.cancel()
    })
    .setPositiveButton(R.string.button_save)
    { dialog, _ ->
        Log.d("Applog", view.toString())
        val songTitle = view?.findViewById<EditText>(R.id.newSongTitle)?.text
        listener.onDialogPositiveClick(songTitle.toString())
    }

在MainActivity.kt

override fun onDialogPositiveClick(songTitle: String) {
    // songTitle has the song title string
}

Android 对话框有一些怪癖。 Here 有多种方法可以进行 fragment/activity 交流。