В настоящее время я использую DataBinding с RecyclerView, и у меня возникает довольно серьезное отставание при первой загрузке списка. Однако после того, как я прокручиваю страницу и она перестает создавать новых просмотрщиков, все в порядке.
Во время создания единственное, что я делаю, это раздуваю макет с помощью DataBindingUtils, поэтому мне интересно, есть ли части, которые можно улучшить.
Ниже приложены соответствующие фрагменты кода. Сейчас я использую библиотеку FastAdapter, поэтому подписи точно не совпадут
При создании вьюхолдера я делаю следующее:
override fun createView(ctx: Context, parent: ViewGroup?): View {
val start = System.nanoTime()
val binding: ViewDataBinding = DataBindingUtil.inflate(
LayoutInflater.from(ctx),
layoutRes, parent,
false,
null
)
L.d { "Create view ${(System.nanoTime() - start) / 1000000}" }
return binding.root
}
Похоже, что для моего более сложного макета вьюхолдеры занимают около 30-60 мс каждый, что приводит к заметному отставанию.
Привязка и отвязка выглядят так:
final override fun bindView(holder: ViewHolder, payloads: MutableList<Any>) {
super.bindView(holder, payloads)
val binding = DataBindingUtil.getBinding<Binding>(holder.itemView) ?: return
binding.bindView(holder, payloads)
binding.executePendingBindings()
}
open fun Binding.bindView(holder: ViewHolder, payloads: MutableList<Any>) {
setVariable(BR.model, data)
}
final override fun unbindView(holder: ViewHolder) {
super.unbindView(holder)
val binding = DataBindingUtil.getBinding<Binding>(holder.itemView) ?: return
binding.unbindView(holder)
binding.unbind()
}
open fun Binding.unbindView(holder: ViewHolder) {}
final override fun getViewHolder(v: View): ViewHolder = ViewHolder(v, layoutRes)
По сути, у меня обычно есть одна модель данных, которую я устанавливаю, и я сам реализую отвязку для каждого вьюхолдера. Кажется, там нет проблемы.
Читая другие статьи, кажется, что у большинства разработчиков такой же метод создания вьюхолдеров, как и у меня. Разве DataUtilBinding не должен выполняться при создании, или я что-то упускаю?
В качестве дополнения, вот мой соответствующий макет xml:
<?xml version = "1.0" encoding = "utf-8"?>
<layout xmlns:android = "http://schemas.android.com/apk/res/android"
xmlns:app = "http://schemas.android.com/apk/res-auto"
xmlns:tools = "http://schemas.android.com/tools">
<data>
<variable
name = "model"
type = "github.fragment.ShortRepoRowItem" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:background = "?android:windowBackground"
android:foreground = "?selectableItemBackground"
android:paddingStart = "@dimen/kau_activity_horizontal_margin"
android:paddingTop = "@dimen/kau_padding_small"
android:paddingEnd = "@dimen/kau_activity_horizontal_margin"
android:paddingBottom = "@dimen/kau_padding_small"
tools:context = ".activity.MainActivity">
<TextView
android:id = "@+id/repo_name"
style = "@style/TextAppearance.AppCompat.Medium"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:text = "@{model.name}"
android:textColor = "?android:textColorPrimary"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent"
tools:text = "@tools:sample/full_names" />
<TextView
android:id = "@+id/repo_desc"
style = "@style/TextAppearance.AppCompat.Caption"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:ellipsize = "end"
android:maxLines = "2"
android:text = "@{model.description}"
android:textColor = "?android:textColorSecondary"
app:goneFlag = "@{model.description}"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@id/repo_name"
tools:text = "@tools:sample/lorem/random" />
<com.google.android.material.chip.Chip
android:id = "@+id/repo_stars"
style = "@style/RepoChips"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
app:chipIcon = "@drawable/ic_star_border"
app:compactNumberText = "@{model.stargazers.totalCount}"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@id/repo_desc"
app:layout_constraintWidth_percent = "0.12"
tools:text = "123" />
<com.google.android.material.chip.Chip
android:id = "@+id/repo_forks"
style = "@style/RepoChips"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
app:chipIcon = "@drawable/ic_fork"
app:compactNumberText = "@{model.forkCount}"
app:layout_constraintStart_toEndOf = "@id/repo_stars"
app:layout_constraintTop_toBottomOf = "@id/repo_desc"
app:layout_constraintWidth_percent = "0.12"
tools:text = "123" />
<com.google.android.material.chip.Chip
android:id = "@+id/repo_issues"
style = "@style/RepoChips"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
app:chipIcon = "@drawable/ic_issues"
app:compactNumberText = "@{model.issues.totalCount}"
app:layout_constraintStart_toEndOf = "@id/repo_forks"
app:layout_constraintTop_toBottomOf = "@id/repo_desc"
app:layout_constraintWidth_percent = "0.12"
tools:text = "1.5k" />
<com.google.android.material.chip.Chip
android:id = "@+id/repo_prs"
style = "@style/RepoChips"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
app:chipIcon = "@drawable/ic_pull_requests"
app:compactNumberText = "@{model.pullRequests.totalCount}"
app:layout_constraintStart_toEndOf = "@id/repo_issues"
app:layout_constraintTop_toBottomOf = "@id/repo_desc"
app:layout_constraintWidth_percent = "0.12"
tools:text = "123" />
<com.google.android.material.chip.Chip
android:id = "@+id/repo_language"
style = "@style/RepoChips"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
android:text = "@{model.primaryLanguage.name}"
app:chipIcon = "@drawable/ic_language"
app:languageColor = "@{model.primaryLanguage.color}"
app:layout_constraintEnd_toStartOf = "@id/repo_date"
app:layout_constraintStart_toEndOf = "@id/repo_prs"
app:layout_constraintTop_toBottomOf = "@id/repo_desc"
app:layout_constraintWidth_percent = "0.25"
tools:text = "JavaScript" />
<com.google.android.material.chip.Chip
android:id = "@+id/repo_date"
style = "@style/RepoChips"
android:layout_width = "0dp"
android:layout_height = "wrap_content"
app:chipIcon = "@drawable/ic_time"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toEndOf = "@id/repo_language"
app:layout_constraintTop_toBottomOf = "@id/repo_desc"
app:relativeDateText = "@{model.pushedAt}"
app:textStartPadding = "4dp"
tools:text = "@tools:sample/date/mmddyy" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Я пытался сделать то же самое с двумя линейными макетами вместо ConstraintLayout, но, похоже, это не имеет большого значения.
Снимок кода: https://github.com/AllanWang/GitDroid/tree/f802c991580d70470b422186fc43f46b9cfe2465
Это под createView. По сути, затем я создаю ViewHolder, передавая возвращаемое представление, и библиотека подключает несколько слушателей (в настоящее время один к itemView, определенно не проблема). Просто при регистрации создание представления составляет 30-60 мс, так что проблема кажется правильной?
Вы пробовали это без привязки данных, используя ту же библиотеку? Я еще не пробовал эту библиотеку, но, похоже, она вызывает у вас проблемы.
Я использовал библиотеку раньше (и вносил в нее свой вклад) без привязки данных, и у меня не было проблем, и я изначально писал свой проект без нее, и тогда у меня все еще были проблемы. Сначала я думал, что это из-за компоновки с ограничениями, но я исключил это, так как попробовал макет без него. Просто для справки: здесь — это мой код до того, как я перешел на FastAdapter.
Я сделал еще несколько измерений и обнаружил, что виновником на самом деле была инфляция макета (т.е. 60 мс), а не просто привязка (т.е. 3 мс).
Чтобы проверить, раздуйте вид как есть без DataBindingUtil, затем вызовите bind на виде.
Отсюда проблема заключалась и в использовании MaterialChips. После переключения 6 чипов материалов на просмотр текста время надувания сократилось в 3 раза и составило примерно 10-30 мс.
Не могли бы вы показать здесь инициализацию вьюхолдера, в большинстве случаев проблема связана с этой частью кода.