android - 所有 ViewHolders 同时创建

标签 android performance android-recyclerview android-adapter

我有 RecyclerView

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipe_task_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/toolbar">

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/scroll_task_list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fillViewport="true">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:focusableInTouchMode="true"
                android:orientation="vertical">

                <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
                    android:id="@+id/rv_task_list"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/background_task_list" />

                <android.support.v4.widget.Space
                    android:layout_width="match_parent"
                    android:layout_height="80dp" />
            </LinearLayout>

        </android.support.v4.widget.NestedScrollView>
    </android.support.v4.widget.SwipeRefreshLayout>

初始化:

rv_task_list.layoutManager = LinearLayoutManager(context)
rv_task_list.layoutManager.setAutoMeasureEnabled(true)
rv_task_list.isNestedScrollingEnabled = false
rv_task_list.adapter = adapter

在适配器中设置数据:

    data.addAll(tasksToAdapter)
    notifyDataSetChanged()

(UPD)适配器:

class TaskAdapter(private val view: ITaskList) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

val data: MutableList<ITaskItem> = mutableListOf()
lateinit var context: Context

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    Log.e("TaskAdapter", "onCreateViewHolder")
    context = parent.context
    if (viewType == TITLE_TYPE) {
        val view = LayoutInflater.from(context).inflate(R.layout.card_title, parent, false);
        return TaskTitleViewHolder(view);
    } else {
        val view = LayoutInflater.from(context).inflate(R.layout.card_task, parent, false);
        return TaskViewHolder(view);
    }

}

override fun getItemViewType(position: Int): Int {
    return data[position].getTaskType()
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) 
{
    Log.e("TaskAdapter", "onBindViewHolder(${position})")
    if (getItemViewType(position) == TITLE_TYPE) {
        (holder as TaskTitleViewHolder).bind(data[position] as TaskTitle)

    }
    else {
        val task = data[position] as Task
        (holder as TaskViewHolder).bind(task)
        holder.itemView.setOnClickListener {
            view.onSelectTask(task.id)
        }
    }

}

fun setData(tasks: List<Task>, showAllTasks: Boolean = false) {
    data.clear()

    val tasksToAdapter: MutableList<ITaskItem> = mutableListOf()
    // List creating
    data.addAll(tasksToAdapter)
    notifyDataSetChanged()
}

override fun getItemCount(): Int = data.size


// ViewHolders

class TaskViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    private val tvTaskInfo: TextView = view.findViewById(R.id.tv_task_info)
    private val tvTaskComments: TextView = view.findViewById(R.id.tv_task_comments)
    private val tvTaskTitle: TextView = view.findViewById(R.id.tv_task_title)
    private val viewHeader: View = view.findViewById(R.id.view_header)
    private val tvEstimate: TextView = view.findViewById(R.id.tv_estimate)
    private val layoutExpectedDate: LinearLayout = view.findViewById(R.id.layout_expected_date)
    private val tvExpectedDate: TextView = view.findViewById(R.id.tv_expected_date)

    private val ivIconComments: ImageView = view.findViewById(R.id.iv_comments_icon)
    private val ivFlagComments: ImageView = view.findViewById(R.id.iv_flag_icon)
    private val ivIconClock: ImageView = view.findViewById(R.id.iv_clock_icon)
    private val layoutDateInformation: LinearLayout = view.findViewById(R.id.layout_date_information)

    fun bind(task: Task) {
        tvTaskInfo.text = "${task.projectName} ${task.id} (${task.type.localization})"

        if (task.commentsUnread == 0) {
            tvTaskComments.setTextColor(getColor(R.color.task_list_font_color_alpha))
            ivIconComments.setImageDrawable(ContextCompat.getDrawable(App.get(), R.drawable.ic_with_readed_message))
        } else {
            tvTaskComments.setTextColor(getColor(R.color.task_list_font_color))
            ivIconComments.setImageDrawable(ContextCompat.getDrawable(App.get(), R.drawable.ic_with_unreaded_message))
        }
        tvTaskComments.text = "${task.commentsUnread}/${task.commentsAll}"

        tvTaskTitle.text = Html.fromHtml(task.title)
        viewHeader.setBackgroundColor(getColorToTaskState(task.status))

        layoutDateInformation.visibility = View.GONE
        if (!(task.status == TaskState.InWork || task.status == TaskState.Negotiation)) {
            return
        }

        if (task.getFormattedExpectedDate().isNotBlank()) {
            tvExpectedDate.text = task.getFormattedExpectedDate()
            layoutExpectedDate.visibility = View.VISIBLE
        }
        else {
            layoutExpectedDate.visibility = View.GONE
        }

        layoutDateInformation.visibility = View.VISIBLE
        ivIconClock.visibility = View.GONE
        if (task.type == TaskType.EstimateRework || task.type == TaskType.Design) {
            with (task.getFormattedEstimateTime()) {
                if (isNotBlank()) {
                    tvEstimate.text = "${App.get().getString(R.string.estimated)} ${task.getFormattedEstimateTime()}"
                    tvEstimate.visibility = View.VISIBLE
                }
                else
                    tvEstimate.visibility = View.GONE
            }

            ivIconClock.visibility = View.VISIBLE
            ivIconClock.setImageDrawable(getImage(R.drawable.ic_clock))
            ivIconClock.setColorFilter(getColor(R.color.task_list_clock_estimated), PorterDuff.Mode.SRC_ATOP)
            ivFlagComments.setImageDrawable(null)
        } else {

            tvEstimate.text = task.roughEstimate ?: ""
            ivIconClock.visibility = View.VISIBLE
            ivIconClock.setImageDrawable(getImage(R.drawable.ic_clock))
            ivFlagComments.setImageDrawable(getImage(R.drawable.ic_flag))
        }

    }
}

class TaskTitleViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    private val tvTaskTitle: TextView = view.findViewById(R.id.tv_tasks_title)
    private val layoutCircle: FrameLayout = view.findViewById(R.id.layout_title_circle)
    private val layoutCircleAdditional: FrameLayout = view.findViewById(R.id.layout_title_circle_additional)


    fun bind(taskTitle: TaskTitle) {
        tvTaskTitle.text = taskTitle.content.toUpperCase()

        setCircle(layoutCircle, taskTitle.taskState)
        if (taskTitle.additionalTaskState != null) {
            layoutCircleAdditional.visibility = View.VISIBLE
            setCircle(layoutCircleAdditional, taskTitle.additionalTaskState!!)
        }
    }

    private fun setCircle(layout: FrameLayout, state: TaskState) {

        if (state == TaskState.WaitToWork) {
            layout.background = getImage(R.drawable.ic_waiting)
        } else {
            val drawable = ContextCompat.getDrawable(App.get(), R.drawable.task_header_circle)
            drawable.setColorFilter(getColorToTaskState(state), PorterDuff.Mode.SRC_ATOP)
            layout.background = drawable
        }

    }
}

我有两种类型的 View Holder。当我在适配器中设置数据时,同时创建所有 ViewHolders(超过 90 个)。 onCreateViewHolderonBindViewHolder 被一一调用了 90 次。

为什么会发生?

最佳答案

我认为您的问题是在 NestedScrollView 中使用 RecyclerViewNestedScrollView 展开以容纳所有内部子项目(在本例中为 RecyclerView) 你可以尝试使用 app:layout_behavior="@string/appbar_scrolling_view_behavior" 但正如官方文档所说

Never add a RecyclerView or ListView to a scroll view. Doing so results in poor user interface performance and a poor user experience.

关于android - 所有 ViewHolders 同时创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45980346/

相关文章:

performance - ZF2 针对高流量进行优化

python - 使用 cython 对 python 中的小数组进行高效的数学操作

javascript - 虚拟 DOM 如何提高 ReactJS 的速度?

java - 在 android 中的 RecyclerView 中保存 ToggleButton 的状态

android - 如何制作 Groupie recylerview 2x2 布局

android - 在其中使用混淆器的导出 android 应用程序时出错

Android:除了第一个 ViewPagers 之外的所有内容都不可见

Android Studio 生成签名的 apk 不适用于构建 0.3.6 - 给出错误

java - 创建内存中的 FileDescriptor

具有包装内容行为的 androidx Recycler View 匹配约束(0dp)