Skip to content

Commit

Permalink
Enable recycling of views within groups (#657)
Browse files Browse the repository at this point in the history
* Enable recycling of views within groups

* cleanup

* revert to kotlin 1.2.71

* fix test
  • Loading branch information
elihart authored Jan 22, 2019
1 parent 784ba33 commit 2de36ba
Show file tree
Hide file tree
Showing 12 changed files with 655 additions and 409 deletions.
5 changes: 4 additions & 1 deletion .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buildscript {
jcenter()
}
dependencies {
classpath "com.android.tools.build:gradle:3.2.1"
classpath "com.android.tools.build:gradle:$ANDROID_PLUGIN_VERSION"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
classpath 'com.bmuschko:gradle-nexus-plugin:2.3.1'
}
Expand Down Expand Up @@ -83,6 +83,6 @@ def getRepositoryPassword() {
}

task wrapper(type: Wrapper) {
gradleVersion = '4.9'
gradleVersion = '4.10.2'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
106 changes: 106 additions & 0 deletions epoxy-adapter/src/main/java/com/airbnb/epoxy/ActivityRecyclerPool.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.airbnb.epoxy

import android.app.Activity
import android.content.Context
import android.os.Build
import androidx.core.view.ViewCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import androidx.recyclerview.widget.RecyclerView
import java.lang.ref.WeakReference
import java.util.ArrayList

internal class ActivityRecyclerPool {

/**
* Store one unique pool per activity. They are cleared out when activities are destroyed, so this
* only needs to hold pools for active activities.
*/
private val pools = ArrayList<PoolReference>(5)

@JvmOverloads
fun getPool(
context: Context,
poolFactory: () -> RecyclerView.RecycledViewPool = { UnboundedViewPool() }
): PoolReference {

val iterator = pools.iterator()
var poolToUse: PoolReference? = null

while (iterator.hasNext()) {
val poolReference = iterator.next()
when {
poolReference.context === context -> {
if (poolToUse != null) {
throw IllegalStateException("A pool was already found")
}
poolToUse = poolReference
// finish iterating to remove any old contexts
}
poolReference.context.isActivityDestroyed() -> {
// A pool from a different activity that was destroyed.
// Clear the pool references to allow the activity to be GC'd
poolReference.viewPool.clear()
iterator.remove()
}
}
}

if (poolToUse == null) {
poolToUse = PoolReference(context, poolFactory(), this)
(context as? LifecycleOwner)?.lifecycle?.addObserver(poolToUse)
pools.add(poolToUse)
}

return poolToUse
}

fun clearIfDestroyed(pool: PoolReference) {
if (pool.context.isActivityDestroyed()) {
pool.viewPool.clear()
pools.remove(pool)
}
}
}

internal class PoolReference(
context: Context,
val viewPool: RecyclerView.RecycledViewPool,
private val parent: ActivityRecyclerPool
) : LifecycleObserver {
private val contextReference: WeakReference<Context> = WeakReference(context)

val context: Context? get() = contextReference.get()

fun clearIfDestroyed() {
parent.clearIfDestroyed(this)
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onContextDestroyed() {
clearIfDestroyed()
}
}

internal fun Context?.isActivityDestroyed(): Boolean {
if (this == null) {
return true
}

if (this !is Activity) {
return false
}

if (isFinishing) {
return true
}

return if (Build.VERSION.SDK_INT >= 17) {
isDestroyed
} else {
// Use this as a proxy for being destroyed on older devices
!ViewCompat.isAttachedToWindow(window.decorView)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ protected BoundViewHolders getBoundViewHolders() {

@Override
public int getItemViewType(int position) {
return viewTypeManager.getViewType(getModelForPosition(position));
return viewTypeManager.getViewTypeAndRememberModel(getModelForPosition(position));
}

@Override
Expand Down
Loading

0 comments on commit 2de36ba

Please sign in to comment.