Reputation: 2951
I'm currently using DataBinding with a RecyclerView, and I'm getting pretty severe lag when a list first loads. However, after I scroll past a page and it stops creating new viewholders, everything is fine.
During creation, the only thing I'm doing is inflating a layout using DataBindingUtils
, so I'm wondering if there are parts that can be improved.
Attached below are relevant code snippets. I'm currently using a library, FastAdapter
, so the signatures will not match exactly
When creating a viewholder, I do the following:
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
}
It appears that for my more complex layout, viewholders take around 30-60 ms each, resulting in notable lag.
Binding and unbinding are like so:
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)
Basically, I usually have a single data model that I set, and I implement unbinding myself per viewholder. There doesn't seem to be a problem there.
Reading other articles, it appears that most developers have the same viewholder creation method as I do. Is DataUtilBinding not meant to be done upon creation, or is there something I'm missing?
As an addition, here is my relevant layout 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>
I've tried doing the same thing with two linear layouts instead of ConstraintLayout, but it doesn't seem to make much of a difference.
Code snapshot: https://github.com/AllanWang/GitDroid/tree/f802c991580d70470b422186fc43f46b9cfe2465
Upvotes: 7
Views: 3506
Reputation: 2951
I did some more measurements and found out that the culprit was actually the layout inflation (ie 60ms) instead of just the binding (ie 3ms).
To verify, inflate the view as is without DataBindingUtil
, then call bind
on the view.
From there, the problem was also the use of MaterialChips. After switching 6 material chips to textviews, inflation time went down 3 folds to around 10-30ms.
Upvotes: 8