简体   繁体   English

如何在 Android [Kotlin] 中观察来自适配器的列表

[英]How to observe a list from Adapter in Android [Kotlin]

In my case I am trying to get a list of String from my Adapter and use it in my Fragment but upon debugging using Logs I found that the list is getting updated inside the onBindViewHolder but not outside it.在我的情况下,我试图从我的适配器中获取一个字符串列表并在我的片段中使用它,但是在使用日志进行调试时,我发现该列表在onBindViewHolder内部而不是在它之外得到更新。 So when I try to access the list from my Fragment I am getting an empty list of String.所以当我尝试从我的片段访问列表时,我得到一个空的字符串列表。

I have spent few hours trying to figure this but can't find a feasible solution.我花了几个小时试图解决这个问题,但找不到可行的解决方案。

My Approach: I am thinking of an approach to save this list in a room table and then query it back in the Fragment.我的方法:我正在考虑一种方法将此列表保存在房间表中,然后在片段中查询它。 Though it may solve the issue but is it the only way?虽然它可以解决问题,但它是唯一的方法吗? Are there any other ways to achieve this result?有没有其他方法可以达到这个结果?

My Adapter我的适配器

class FloorProfileDialogAdapter() : RecyclerView.Adapter<FloorProfileDialogAdapter.MyViewHolder>() {

    var floors = emptyList<String>()

    inner class MyViewHolder(val binding: ScheduleFloorDialogItemBinding) :
        RecyclerView.ViewHolder(binding.root)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val binding = ScheduleFloorDialogItemBinding.inflate(inflater, parent, false)

        return MyViewHolder(binding)
    }

    private val checkedFloors: MutableList<String> = mutableListOf()

    //List of uniquely selected checkbox to be observed from New Schedule Floor Fragment
    var unique: List<String> = mutableListOf()

    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val currentFloor = floors[position]
        Timber.d("Current floor: $currentFloor")
        holder.binding.floorCheckBox.text = "Floor $currentFloor"

        //Checks the checked boxes and updates the list
        holder.binding.floorCheckBox.setOnCheckedChangeListener {   buttonView, isChecked ->
            if (buttonView.isChecked) {
                Timber.d("${buttonView.text} checked")
                checkedFloors.add(buttonView.text.toString())
            } else if (!buttonView.isChecked) {
                Timber.d("${buttonView.text} unchecked")
                checkedFloors.remove(buttonView.text)
            }
            unique = checkedFloors.distinct().sorted()
            Timber.d("List: $unique")
        }
    }
    
    fun returnList(): List<String> {
        Timber.d("$unique")
        return unique
    }

    override fun getItemCount(): Int {
        return floors.size
    }

    @SuppressLint("NotifyDataSetChanged")
    fun getAllFloors(floorsReceived: List<String>) {
        Timber.d("Floors received : $floorsReceived")
        this.floors = floorsReceived
        notifyDataSetChanged()
    }
}

Fragment code where I am trying to read it我试图阅读的片段代码

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        //Chosen Floors
        val chosenFloors = floorProfileDialogAdapter.returnList()
        Timber.d("Chosen floors : $chosenFloors")
}

Note: The list I am trying to receive is var unique: List<String> = mutableListOf .注意:我试图接收的列表是var unique: List<String> = mutableListOf I tried to get it using the returnList() but the log in that function shows that list is empty.我尝试使用returnList()获取它,但 function 的日志显示该列表为空。 Similarly the Log in fragment shows that it received an empty list.同样,登录片段显示它收到了一个空列表。

Edit 1: Class to fill the Adapter Floors using getAllFloors()编辑 1:Class 使用getAllFloors()填充适配器楼层

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val floorList: MutableList<String> = mutableListOf()

        var profileName: String? = ""
        profileName = args.profileName
        
        //Profile name received
        Timber.d("Profile name : $profileName")

        //Getting list of all floors
        createProfileViewModel.totalFloors.observe(viewLifecycleOwner) {
            Timber.d("List of floors received : $it")

            val intList = it.map(String::toInt)
            val maxFloorValue = intList.last()
            var count = 0

            try {
                while (count <= maxFloorValue) {
                    floorList.add(count.toString())
                    count++
                }
            } catch (e: Exception) {
                Timber.d("Exception: $e")
            }
            floorProfileDialogAdapter.getAllFloors(floorList)
            Timber.d("Floor List : $floorList")
        }

When you first set up your Fragment and create your Adapter, unique is empty:当您第一次设置 Fragment 并创建 Adapter 时, unique为空:

var unique: List<String> = mutableListOf()

(if you have some checked state you want to save and restore, you'll have to initialise this with your checked data) (如果您有一些检查过的 state 想要保存和恢复,则必须使用检查过的数据对其进行初始化)

In onViewCreated , during Fragment setup, you get a reference to this (empty) list:onViewCreated中,在 Fragment 设置期间,您会获得对此(空)列表的引用:

// Fragment onViewCreated
val chosenFloors = floorProfileDialogAdapter.returnList()

// Adapter
fun returnList(): List<String> {
    return unique
}

So chosenFloors is a reference to this initial entry list.所以chosenFloors是对这个初始条目列表的引用。 But when you actually update unique in onBindViewHolder但是当你真正更新onBindViewHolder中的unique

unique = checkedFloors.distinct().sorted()

you're replacing the current list with a new list object.您正在用列表 object 替换当前列表。 You're not updating the existing list (even though you made it a MutableList ).您没有更新现有列表(即使您将其MutableList )。 So you never actually add anything to that empty list you started with, and chosenFloors is left pointing at a list that contains nothing, while the Adapter has discarded it and unique holds a completely different object.因此,您实际上从未向您开始的那个空列表添加任何内容,并且chosenFloors指向一个不包含任何内容的列表,而适配器已丢弃它并且unique拥有完全不同的 object。


The solution there is to make unique a val (so you can't replace it) and just change its contents, eg解决方案是制作uniqueval (因此您无法替换它)并仅更改其内容,例如

unique.clear()
unique += checkedFloors.distinct().sorted()

But I don't feel like that's your problem.但我不觉得那是你的问题。 Like I pointed out, that list is initially empty anyway, and you're grabbing it in your Fragment during initialisation just so you can print out its contents, as though you expect it to contain something at that point.就像我指出的那样,该列表最初是的,并且您在初始化期间将其抓取到 Fragment 中,以便您可以打印出它的内容,就好像您希望它此时包含某些内容一样。 Unless you initialise it with some values, it's gonna be empty.除非你用一些值初始化它,否则它将是空的。

If you're not already storing/restoring them, you'll need to handle that!如果您还没有存储/恢复它们,则需要处理它! I posted some code to do that on another answer so I'll just link that instead of repeating myself.我在另一个答案上发布了一些代码来做到这一点,所以我只是链接它而不是重复自己。 That code is storing indices though, not text labels like you're doing.不过,该代码正在存储索引,而不是像您正在做的文本标签。 Indices are much cleaner and avoid errors - the text is more of a display thing, a property of the item the specific (and unique) index refers to.索引更清晰并避免错误 - 文本更多的是显示内容,特定(和唯一)索引所指的项目的属性。 (But you can store a string array in SharedPreferences if you really want to.) (但如果你真的想的话,你可以在SharedPreferences中存储一个字符串数组。)


Also you're not actually updating your ViewHolder to display the checked state for the current item in onBindViewHolder .此外,您实际上并没有更新ViewHolder以显示 onBindViewHolder 中当前项目的选中onBindViewHolder So whatever ViewHolder you happen to have been given (there's only a few of them for the list, they get reused) it's just showing whatever its checkbox was last set to, by you poking at it.因此,无论您碰巧获得了什么ViewHolder (列表中只有少数几个,它们都会被重用),它只是显示它的复选框最后设置的任何内容,通过您戳它。 Check an item, then scroll the list and see what happens!检查一个项目,然后滚动列表,看看会发生什么!

So you need to check or uncheck the box so it's correct for the item you're displaying.因此,您需要选中或取消选中该框,以便它对您正在显示的项目是正确的。 This is pretty easy if you're storing the checked items by indices:如果您按索引存储检查的项目,这非常容易:

// explicitly set the checked state, depending on whether the item at 'position' is checked
holder.binding.floorCheckBox.checked = checkedItems[position]

You can work out something similar for your text label approach, but again I wouldn't recommend doing things that way.您可以为您的文本 label 方法制定类似的方法,但我不建议这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从Kotlin Android中的适配器启动活动 - How to start activity from adapter in kotlin android 如何观察 LiveData<pagedlist> 在 kotlin 中使用 android 分页</pagedlist> - How to observe LiveData<PagedList> with android paging in kotlin 如何从适配器获取变量值到android kotlin recyclerview中的活动? - How to get the variable value from adapter to activities in android kotlin recyclerview? android - 如何将侦听器从片段传递给适配器? (科特林) - android - How to pass listener to an Adapter from a Fragment? (Kotlin) 如何从 android kotlin 中的 recyclerview 适配器获取 arraylist - How to get arraylist from recyclerview adapter in android kotlin 如何使用 kotlin 从 android 适配器 recyclerview 拨打电话 - how to make a phone call from android adapter recyclerview using kotlin 我尝试从我的应用程序和 Kotlin Android 中的 FireStore 中删除 recyclerView 列表。 我如何在我的适配器中调用删除代码? - I try to delete the recyclerView list from my app and FireStore in Kotlin Android. How can ı call the remove code in my Adapter? 如何让 LiveData 在 Android [Kotlin] 中只观察一次 - How to make LiveData observe only once in Android [Kotlin] 如何使用 Kotlin 的自定义适配器为列表视图设置 OnItemClickListener - How to setOnItemClickListener for List View with custom adapter by Kotlin 如何在 RecyclerView 适配器中为 Kotlin 中的 Android 初始化 viewHolder - How to initialize viewHolder in RecyclerView adapter for Android in Kotlin
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM