【问题标题】:How to rebind item in RecyclerView when the data changed in Kotlin?当 Kotlin 中的数据发生变化时,如何在 RecyclerView 中重新绑定项目?
【发布时间】:2018-09-13 15:36:30
【问题描述】:

我自定义了一个 RecyclerView 类,它将在代码 B 的 Kotlin 中显示 val backupItemList: List<MSetting> 的内容

现在我在RecyclerView类外面修改backupItemList的数据,我认为Code D会在UI中显示最新的数据,但是我失败了,UI仍然是显示旧的数据。 我必须使用 Code C 来显示最新数据。

代码 D 有什么问题?

代码 A

class UIMain : AppCompatActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_main)                       

        allList= SettingHandler().getListAllSetting()            

        mRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
        mCustomAdapter= CustomAdapter(allList)
        mRecyclerView.adapter= mCustomAdapter


   }


   public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
       //Code C          
       if (resultCode == RESULT_OK) {
           allList=SettingHandler().getListAllSetting()
           mCustomAdapter= CustomAdapter(allList)
           mRecyclerView.adapter= mCustomAdapter
           mCustomAdapter.notifyDataSetChanged()
           mCustomAdapter.setSelectedItem(selectedBackupItem)  
       }


       //Code D     
       if (resultCode == RESULT_OK) {
          allList=SettingHandler().getListAllSetting()                
          mCustomAdapter.setSelectedItem(selectedBackupItem)                
       }         

   }        

}

代码 B

  class CustomAdapter (val backupItemList: List<MSetting>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

        val noRecord=-1
        private var mSelectedItem = noRecord

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
            val v = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview, parent, false)
            return ViewHolder(v)
        }

        fun getSelectedItem():Int{
            return  mSelectedItem
        }

        fun setSelectedItem(index:Int){
            if (index in 0..(backupItemList.size-1) ){
                mSelectedItem=index
                notifyDataSetChanged();
            }

        }

        override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
            holder.bindItems(backupItemList[position])
        }

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

        inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

            fun bindItems(aMSetting: MSetting) {
                itemView.tvSubject.text=aMSetting.name
                itemView.tvCreatedDate.text=aMSetting.createdDate.toDateString()
                itemView.tvDescription.text=aMSetting.description   
                itemView.radioButton.setOnClickListener {
                mSelectedItem=adapterPosition
                notifyDataSetChanged();
            }

            if(adapterPosition == 0 && mSelectedItem == noRecord) {             
                itemView.radioButton.isChecked = true
                mSelectedItem=adapterPosition
            }
            else {
                itemView.radioButton.isChecked =(adapterPosition == mSelectedItem)
            }       
            }

        }

    }

致 civic.LiLister:

如果我使用代码 E(我将 val 替换为 var),代码 C 和代码 D 都会得到相同的结果,为什么?

代码 E

  class CustomAdapter (var backupItemList: List<MSetting>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

        val noRecord=-1
        private var mSelectedItem = noRecord

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
            val v = LayoutInflater.from(parent.context).inflate(R.layout.item_recyclerview, parent, false)
            return ViewHolder(v)
        }

        fun getSelectedItem():Int{
            return  mSelectedItem
        }

        fun setSelectedItem(index:Int){
            if (index in 0..(backupItemList.size-1) ){
                mSelectedItem=index
                notifyDataSetChanged();
            }

        }

        override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
            holder.bindItems(backupItemList[position])
        }

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

        inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

            fun bindItems(aMSetting: MSetting) {
                itemView.tvSubject.text=aMSetting.name
                itemView.tvCreatedDate.text=aMSetting.createdDate.toDateString()
                itemView.tvDescription.text=aMSetting.description   
                itemView.radioButton.setOnClickListener {
                mSelectedItem=adapterPosition
                notifyDataSetChanged();
            }

            if(adapterPosition == 0 && mSelectedItem == noRecord) {             
                itemView.radioButton.isChecked = true
                mSelectedItem=adapterPosition
            }
            else {
                itemView.radioButton.isChecked =(adapterPosition == mSelectedItem)
            }       
            }

        }

    }

【问题讨论】:

  • 请明确您的观点,您在哪里更改来自服务器的数据?
  • 从 UI,我通过 UI 编辑 allList
  • 来自另一个活动?
  • 是的。从另一个活动,我使用public override fun onActivityResult 来处理结果
  • 清除一个点,您想在列表中添加更多项目还是编辑之前添加的项目?

标签: android android-recyclerview kotlin


【解决方案1】:

秘密可能隐藏在这里:

类 CustomAdapter (val backupItemList: List)

当您初始化 CustomAdapter 的实例时,该值被复制到属性 backupItemList,而不是分配引用。因此,当您更改 UIMain 的 allList 属性时,backupItemList 不会像您预期的那样发生变化。

解决方案很简单,正如 Ganesh Tikone 所写:添加一个方法来更新 backupItemList。

fun updateData(data: List<MovieModel>) {
    backupItemList.clear()
    backupItemList.addAll(data)
    notifyDataSetChanged()
}

并将代码 D 更改为:

//Code D     
   if (resultCode == RESULT_OK) {
      allList=SettingHandler().getListAllSetting()  
      mCustomAdapter.updateData(allList)    
      mCustomAdapter.setSelectedItem(selectedBackupItem)                
   }  

试一试。

【讨论】:

  • 谢谢!请看我修改后的问题,当我使用class CustomAdapter (var backupItemList: List)时,代码 C 和代码 D 得到相同的结果@
  • 当我初始化一个CustomAdapter (var backupItemList: List)的实例时,我认为会为backupItemList分配一个引用,对吧?
  • 还有,allList 是 List 而不是 MutableList,不能调用 allList.clear() 和 allList.addAll()
  • Replace val with var for property backupItemList: List 不是一个好习惯,我认为。虽然它适用于您当前的项目。在函数式编程中,我们应该限制可变数据的使用。我们应该尝试使函数成为纯函数。 var 类似于“全局”变量。这可能会从适配器中更改出来,并且可能会导致难以修复的奇怪错误。
【解决方案2】:

在您的 Activity onCreate 方法中

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.layout_main)                
    
            allList = ArrayList< MSetting>()
            mCustomAdapter = CustomAdapter(mChildList)
            mRecyclerView.layoutManager = LinearLayoutManager(context)
            mRecyclerView.adapter = mCustomAdapter
    }

现在在 onActivityResult

     public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {

           //Code C          
           if (resultCode == RESULT_OK) {
              if(data != null){
                 allList.clear()
                 allList.addAll(SettingHandler().getListAllSetting())
                 mCustomAdapter.notifyDataSetChanged()
                 mCustomAdapter.setSelectedItem(selectedBackupItem) 
              } 
           }
        
      }        

【讨论】:

    【解决方案3】:

    在您的代码 D 中,您覆盖了 allList 的引用

    CustomAdapter 中的 backupItemList 也有相同的参考。 因此,如果您重新分配 allList 的引用,则不会在回收站视图中获取更改

    首先确保 allList 是可变的

    val allList = mutableListOf<MSetting>()
    

    然后在代码 D 中

    allList.clear()
    allList.addAll(SettingHandler().getListAllSetting())
    mCustomAdapter.notifyDataSetChanged()
    

    【讨论】:

      【解决方案4】:

      检查此代码,

      if (resultCode == RESULT_OK) {
                 allList.clear()
                 allList=SettingHandler().getListAllSetting()
                 mCustomAdapter= CustomAdapter(allList)
                 mRecyclerView.adapter= mCustomAdapter  
                 mCustomAdapter.setSelectedItem(selectedBackupItem) 
             }
      

      【讨论】:

      • 记得在onActivityResult()的日志中查看你的列表是否有数据。
      • 谢谢!但是您的代码就像我的代码 C,我认为也许有更好的方法
      • 我认为你不需要运行allList.clear(),因为allList=SettingHandler().getListAllSetting()会自动清除旧数据
      • onActivityResult() 是否返回 RESULT_OK?
      • 如果我在另一个活动中成功编辑了一条记录,我将分配RESULT_OK并将其返回给主活动
      【解决方案5】:

      问题是你没有使用任何binding,这意味着当你修改list时,Adapter不会意识到这一点,因此它只是显示旧项目,但是一旦你通知adapter关于更改您的列表使用notifyDatasetChanged,它将尝试使用新数据刷新项目。如果你想用code D实现功能,你需要使用Data Binding using Observable pattern。更多信息RecyclerView and Data Binding

      【讨论】:

      • 我认为代码notifyDataSetChanged();应该重新绑定基于修改过的allList的items,但实际上系统并没有这样做
      • 还有更多,您能否向我展示一些示例代码,以使用关于我的问题的 Observable 模式使用数据绑定?
      【解决方案6】:

      片段代码

      private var adapter: RecentMovieAdapter? = null
      

      Adapter在fragment的onCreateView方法中初始化

      adapter = RecentMovieAdapter(activity, this)
      

      这是Fragment中的回调方法,使用线程技术从Server获取数据

      override fun onDataReceived(randomDialog: List<MovieModel>) {
          shimmerView!!.stopShimmerAnimation()
          shimmerView!!.visibility = View.GONE
          adapter!!.updateData(randomDialog)
      }
      

      适配器类代码

      private var movieList: MutableList<MovieModel> = mutableListOf<MovieModel>()
      

      像这样在Adapter类中添加更新函数

      fun updateData(data: List<MovieModel>) {
          movieList.clear()
          movieList.addAll(data)
          notifyDataSetChanged()
      }
      

      【讨论】:

        【解决方案7】:

        yourAdapter().notifyDataSetChanged

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-10-20
          • 2021-10-27
          • 1970-01-01
          相关资源
          最近更新 更多