Skip to content

Commit 00d57f2

Browse files
Merge pull request #15902 from nextcloud/perf/gallery-row-holder-caching
perf: gallery row holder caching
2 parents d1c80d5 + 006fc5a commit 00d57f2

File tree

2 files changed

+80
-51
lines changed

2 files changed

+80
-51
lines changed

app/src/main/java/com/owncloud/android/ui/adapter/GalleryRowHolder.kt

Lines changed: 78 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ package com.owncloud.android.ui.adapter
1010

1111
import android.view.Gravity
1212
import android.view.View
13+
import android.view.ViewGroup
1314
import android.widget.FrameLayout
1415
import android.widget.ImageView
1516
import androidx.core.content.ContextCompat
@@ -44,32 +45,55 @@ class GalleryRowHolder(
4445
val context = galleryAdapter.context
4546

4647
private lateinit var currentRow: GalleryRow
48+
49+
// Cached values
4750
private val zero by lazy { context.resources.getInteger(R.integer.zero) }
4851
private val smallMargin by lazy { context.resources.getInteger(R.integer.small_margin) }
4952
private val iconRadius by lazy { context.resources.getDimension(R.dimen.activity_icon_radius) }
5053
private val standardMargin by lazy { context.resources.getDimension(R.dimen.standard_margin) }
5154
private val checkBoxMargin by lazy { context.resources.getDimension(R.dimen.standard_quarter_padding) }
5255

53-
fun bind(row: GalleryRow) {
54-
currentRow = row
56+
private val defaultBitmap by lazy {
57+
val fileDrawable = ResourcesCompat.getDrawable(context.resources, R.drawable.file_image, null)
58+
val thumbnailSize = defaultThumbnailSize.toInt()
59+
BitmapUtils.drawableToBitmap(fileDrawable, thumbnailSize, thumbnailSize)
60+
}
5561

56-
// re-use existing ones
57-
while (binding.rowLayout.childCount < row.files.size) {
58-
val rowLayout = getRowLayout()
59-
binding.rowLayout.addView(rowLayout)
62+
private val checkedDrawable by lazy {
63+
ContextCompat.getDrawable(context, R.drawable.ic_checkbox_marked)?.also {
64+
viewThemeUtils.platform.tintDrawable(context, it, ColorRole.PRIMARY)
6065
}
66+
}
67+
68+
private val uncheckedDrawable by lazy {
69+
ContextCompat.getDrawable(context, R.drawable.ic_checkbox_blank_outline)
70+
}
6171

62-
if (binding.rowLayout.childCount > row.files.size) {
63-
binding.rowLayout.removeViews(row.files.size, binding.rowLayout.childCount - row.files.size)
72+
private var lastFileCount = -1
73+
// endregion
74+
75+
fun bind(row: GalleryRow) {
76+
currentRow = row
77+
val requiredCount = row.files.size
78+
79+
// Only rebuild if file count changed
80+
if (lastFileCount != requiredCount) {
81+
binding.rowLayout.removeAllViews()
82+
repeat(requiredCount) { binding.rowLayout.addView(getRowLayout()) }
83+
lastFileCount = requiredCount
6484
}
6585

6686
val shrinkRatio = computeShrinkRatio(row)
6787

68-
for (indexedFile in row.files.withIndex()) {
69-
adjustFile(indexedFile, shrinkRatio, row)
88+
for (i in row.files.indices) {
89+
adjustFile(i, row.files[i], shrinkRatio, row)
7090
}
7191
}
7292

93+
fun updateRowVisuals() {
94+
bind(currentRow)
95+
}
96+
7397
private fun getRowLayout(): FrameLayout {
7498
val checkbox = ImageView(context).apply {
7599
visibility = View.GONE
@@ -89,16 +113,15 @@ class GalleryRowHolder(
89113
invalidate()
90114
}
91115

92-
val fileDrawable = ResourcesCompat.getDrawable(context.resources, R.drawable.file_image, null)
93-
val thumbnailSize = defaultThumbnailSize.toInt()
94-
val bitmap = BitmapUtils.drawableToBitmap(fileDrawable, thumbnailSize, thumbnailSize)
95116
val drawable = ThumbnailsCacheManager.AsyncGalleryImageDrawable(
96117
context.resources,
97-
bitmap,
118+
defaultBitmap,
98119
null
99120
)
100121
val rowCellImageView = ImageView(context).apply {
101122
setImageDrawable(drawable)
123+
adjustViewBounds = true
124+
scaleType = ImageView.ScaleType.FIT_XY
102125
}
103126

104127
return FrameLayout(context).apply {
@@ -108,10 +131,6 @@ class GalleryRowHolder(
108131
}
109132
}
110133

111-
fun redraw() {
112-
bind(currentRow)
113-
}
114-
115134
@SuppressWarnings("MagicNumber")
116135
private fun computeShrinkRatio(row: GalleryRow): Float {
117136
val screenWidth = DisplayUtils.convertDpToPixel(
@@ -148,20 +167,14 @@ class GalleryRowHolder(
148167
return (screenWidth / galleryAdapter.columns) / width
149168
}
150169

151-
private fun adjustFile(indexedFile: IndexedValue<OCFile>, shrinkRatio: Float, row: GalleryRow) {
152-
val file = indexedFile.value
153-
val index = indexedFile.index
154-
170+
private fun adjustFile(index: Int, file: OCFile, shrinkRatio: Float, row: GalleryRow) {
155171
val width = file.imageDimension?.width?.times(shrinkRatio)?.toInt() ?: 0
156172
val height = file.imageDimension?.height?.times(shrinkRatio)?.toInt() ?: 0
157173

158174
val frameLayout = binding.rowLayout[index] as FrameLayout
159-
val checkBoxImageView = frameLayout[2] as ImageView
160175
val shimmer = frameLayout[0] as LoaderImageView
161-
val thumbnail = (frameLayout[1] as ImageView).apply {
162-
adjustViewBounds = true
163-
scaleType = ImageView.ScaleType.FIT_XY
164-
}
176+
val thumbnail = frameLayout[1] as ImageView
177+
val checkBoxImageView = frameLayout[2] as ImageView
165178

166179
val isChecked = ocFileListDelegate.isCheckedFile(file)
167180

@@ -176,43 +189,59 @@ class GalleryRowHolder(
176189
width
177190
)
178191

192+
// Update layout params only if they differ
193+
val thumbLp = thumbnail.layoutParams
194+
if (thumbLp.width != width || thumbLp.height != height) {
195+
thumbnail.layoutParams = thumbLp.getFrameLayout(width, height).apply {
196+
val endMargin = if (index < row.files.size - 1) smallMargin else zero
197+
this.setMargins(zero, zero, endMargin, smallMargin)
198+
}
199+
}
200+
201+
val shimmerLp = shimmer.layoutParams
202+
if (shimmerLp.width != width || shimmerLp.height != height) {
203+
shimmer.layoutParams = shimmerLp.getFrameLayout(width, height)
204+
}
205+
179206
// Force layout update
180207
frameLayout.requestLayout()
208+
}
181209

182-
val params = FrameLayout.LayoutParams(width, height)
183-
val endMargin = if (index < row.files.size - 1) smallMargin else zero
184-
params.setMargins(zero, zero, endMargin, smallMargin)
185-
186-
thumbnail.layoutParams = params
187-
shimmer.layoutParams = FrameLayout.LayoutParams(params)
210+
private fun ViewGroup.LayoutParams?.getFrameLayout(width: Int, height: Int): FrameLayout.LayoutParams = (
211+
this as? FrameLayout.LayoutParams
212+
?: FrameLayout.LayoutParams(width, height)
213+
).apply {
214+
this.width = width
215+
this.height = height
188216
}
189217

190218
@Suppress("MagicNumber")
191219
private fun adjustRowCell(imageView: ImageView, isChecked: Boolean) {
192-
imageView.apply {
193-
scaleX = if (isChecked) 0.8f else 1.0f
194-
scaleY = scaleX
195-
makeRounded(context, if (isChecked) iconRadius else 0f)
220+
val scale = if (isChecked) 0.8f else 1.0f
221+
val radius = if (isChecked) iconRadius else 0f
222+
223+
// Only update if values changed
224+
if (imageView.scaleX != scale) {
225+
imageView.scaleX = scale
226+
imageView.scaleY = scale
196227
}
228+
229+
imageView.makeRounded(context, radius)
197230
}
198231

199232
private fun adjustCheckBox(imageView: ImageView, isChecked: Boolean) {
200233
if (ocFileListDelegate.isMultiSelect) {
201-
val checkboxDrawable = (
202-
if (isChecked) {
203-
val drawable = ContextCompat.getDrawable(context, R.drawable.ic_checkbox_marked)
204-
drawable?.let {
205-
viewThemeUtils.platform.tintDrawable(context, drawable, ColorRole.PRIMARY)
206-
}
207-
drawable
208-
} else {
209-
ContextCompat.getDrawable(context, R.drawable.ic_checkbox_blank_outline)
210-
}
211-
)?.apply {
234+
val checkboxDrawable = if (isChecked) checkedDrawable else uncheckedDrawable
235+
236+
checkboxDrawable?.apply {
212237
val margin = standardMargin.toInt()
213238
setBounds(margin, margin, margin, margin)
214239
}
215-
imageView.setImageDrawable(checkboxDrawable)
240+
241+
// Only set if different
242+
if (imageView.drawable !== checkboxDrawable) {
243+
imageView.setImageDrawable(checkboxDrawable)
244+
}
216245
}
217246

218247
imageView.setVisibleIf(ocFileListDelegate.isMultiSelect)

app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ class OCFileListDelegate(
196196
}
197197

198198
override fun onNewGalleryImage() {
199-
Log_OC.d(tag, "setGalleryImage.redraw()")
200-
galleryRowHolder.redraw()
199+
Log_OC.d(tag, "updateRowVisuals")
200+
galleryRowHolder.updateRowVisuals()
201201
}
202202

203203
override fun onError() {

0 commit comments

Comments
 (0)