【问题标题】:Problems with nested recyclerview嵌套recyclerview的问题
【发布时间】:2018-11-27 10:28:51
【问题描述】:

我有一个嵌套的 recyclerview,它应该看起来像

我是按照this helpful site实现的。

问题是,有时我的用户拥有数百个项目,在这种情况下,打开活动需要半分钟。

我在后端有一个房间数据库,其中包含两个带有外键(用户和项目)的链接表,我选择所有用户以获取用户/项目列表,其中项目是用户表中的列表。

class userWithItems: (id: Int, name: String, ... ,List)

然后我使用适配器中的项目列表创建内部回收器视图。

创建一个 List UserItems (userid:Int, username:String, ... itemid:Int, itemList) 并将它们分组到外部 rv 会更好吗?

或者是否有可能摆脱嵌套的 rv 并仅使用一个 recyclerview-list 进行设计?

或者是否有其他解决方案可以让嵌套的回收视图工作,即使用户有很多项目?

适配器代码:

// Code in Activity: (oncreate)

val recyclerView = findViewById<RecyclerView>(R.id.rv_users)
val adapter = UserAdapter(this)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)

mainViewModel = ViewModelProviders.of(this, PassIntViewModelFactory(this.application, online_id)).get(MainViewModel::class.java!!)
mainViewModel.userList.observe(this, Observer {
    it?.let {
        adapter.setUserList(it)
    }
})

数据类UsersWithItems(

    val id:Int, val username: String, val address, // fields from user table
    val items: List<Items>   // list of items for current user

)

数据类项目 ( val id: Int, val itemtext: String, val itemlocation: String, val image: String // ... )

// UserAdapter(外部)

类 UserAdapter 内部构造函数( 上下文:上下文 ) : RecyclerView.Adapter() {

private val inflater: LayoutInflater = LayoutInflater.from(context)
private var userList = emptyList<UsersWithItems>()

inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val username: TextView = itemView.findViewById(R.id.user_name)
    val num_pos: TextView = itemView.findViewById(R.id.user_num_pos)
    val address: TextView = itemView.findViewById(R.id.user_addr)
    val rv:RecyclerView = itemView.findViewById(R.id.rv_user_items)
}


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
    val myItemView = inflater.inflate(R.layout.rv_row_user, parent, false)
    return MyViewHolder(myItemView)
}

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
    val current = userList[position]
    holder.username.text="${current.user?.username}"
    holder.num_pos.text="${current.items?.size}"
    holder.address.text = "${current.user?.address}"

    val adapter = UserItemAdapter(holder.rv.context)
    adapter.setItems(current.items!!)
    holder.rv.adapter = adapter
    holder.rv.layoutManager = LinearLayoutManager(holder.rv.context,LinearLayout.VERTICAL,false)

}
internal fun setUserList(userList: List<UsersWithItems>){
    this.userList=userList
    notifyDataSetChanged()
}
override fun getItemCount() = userList.size

}

类 UserItemAdapter 内部构造函数( 上下文:上下文 ) : RecyclerView.Adapter() {

private val inflater: LayoutInflater = LayoutInflater.from(context)
private var itemList = emptyList<Items>()

inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val itemtext: TextView = itemView.findViewById(R.id.item_text)
    val itemlocation:TextView = itemView.findViewById(R.id.item_location)
    val image: ImageView = itemView.findViewById(R.id.item_image)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
    val myItemView = inflater.inflate(R.layout.rv_row_user_items, parent, false)
    return MyViewHolder(myItemView)
}

override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
    val current = itemList[position]
    holder.itemtext.text="${current.itemtext}"
    holder.itemlocation.text = current.itemlocation
    if (current.image.length>0) {
        val image = Base64.decode(current.image, 0)
        val bitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
        holder.image.setImageBitmap(bitmap)
    }
}
internal fun setItems(items: List<Items>){
    this.itemList=items
    notifyDataSetChanged()
}

override fun getItemCount() = itemList.size

}

【问题讨论】:

  • 对不起 - 我不认为代码会是大问题,而是概念,因为它只适用于内部适配器中的几个项目。
  • 我认为问题在于,在内部回收视图中,即使有 1000 个项目并且在显示器上只能看到 5 或 6 个项目,每个项目都会立即创建,这需要时间。

标签: android performance android-recyclerview kotlin nested


【解决方案1】:

E.路透社我经历过这种情况,使用嵌套回收器视图的方法是非常正确的。你的代码似乎很好。但是您用来查询数据库的查询。我认为您应该在后台或其他线程中使用查询并在获得结果时显示结果,而不是从 OnCreate 或主线程中查询。因为一次性获得这么多项目可能会导致活动滞后并降低性能。如果你还没有试试这个,让我知道。发生什么了。谢谢...

我正在编辑我的答案。你可以做的另一件事是,如果你有超过一定数量的项目,那么你应该使用分页之类的东西来一次加载一定数量的项目,而不是一开始就得到它们,以避免这种滞后。

这里我附上代码来查询每次加载的一定数量的数据......

SApp.database!!.resultDao().loadAllUsersByPage(5, 10)
 @Query("SELECT * FROM Result LIMIT :limit OFFSET :offset")
 fun loadAllUsersByPage(limit: Int, offset: Int): List<Result>

【讨论】:

    【解决方案2】:

    非常感谢您的回答。我认为分页确实是一个好方法。但是我不能直接添加分页,因为我是从这样的房间数据库中获取数据的:

    @Query(SELECT * FROM users)
    fun getData(): LiveData<List<userWithItems>>
    

    由于用户和项目之间的关系,实际项目是按房间添加的,我将不得不改变这种行为。

    我会尝试类似的东西

    @Query(SELECT * FROM users)
    fun getUserData(): LiveData<List<Users>>
    

    然后尝试在外部 recyclerview 中添加一个 LiveData 观察者,以便在使用分页的单独查询中获取项目。

    【讨论】:

      【解决方案3】:

      我解决了这个问题。当我想到分页时,我想到问题可能是内部 recyclerview 的高度为 wrap_content ,因此它需要构建所有项目并使 rv 无用。当我将内部 rv 的高度设置为 250dp 时,它甚至可以处理 2000 个项目。

      所以现在我只需要找出一种方法来始终找到内部 rv 的最佳高度并解决滚动问题,但原来的问题已经解决了。

      特别感谢 Aman B!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-31
        相关资源
        最近更新 更多