Add parent id to decor view
Summary: This whole nested observer approach can be simplified massively, but for now we are just threading the parent id through so its set for observer roots too Reviewed By: lblasa Differential Revision: D47915504 fbshipit-source-id: 924f722f38bb202b42ea9ef6da15e685f6c75e02
This commit is contained in:
committed by
Facebook GitHub Bot
parent
413f85964b
commit
6b74f66ab4
@@ -13,6 +13,7 @@ import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||
import com.facebook.flipper.plugins.uidebugger.core.ApplicationRef
|
||||
import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
import com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
||||
|
||||
/**
|
||||
@@ -23,7 +24,7 @@ class ApplicationTreeObserver(val context: UIDContext) : TreeObserver<Applicatio
|
||||
|
||||
override val type = "Application"
|
||||
|
||||
override fun subscribe(node: Any) {
|
||||
override fun subscribe(node: Any, parentId: Id?) {
|
||||
Log.i(LogTag, "Subscribing activity / root view changes")
|
||||
|
||||
val applicationRef = node as ApplicationRef
|
||||
@@ -41,7 +42,7 @@ class ApplicationTreeObserver(val context: UIDContext) : TreeObserver<Applicatio
|
||||
}
|
||||
|
||||
context.sharedThrottle.registerCallback(this.objectIdentity()) {
|
||||
traverseAndSend(context, applicationRef)
|
||||
traverseAndSend(null, context, applicationRef)
|
||||
}
|
||||
|
||||
context.applicationRef.rootsResolver.attachListener(rootViewListener)
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.view.ViewTreeObserver
|
||||
import com.facebook.flipper.plugins.uidebugger.LogTag
|
||||
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
||||
import com.facebook.flipper.plugins.uidebugger.descriptors.Id
|
||||
import com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
@@ -26,14 +27,14 @@ class DecorViewObserver(val context: UIDContext) : TreeObserver<DecorView>() {
|
||||
|
||||
override val type = "DecorView"
|
||||
|
||||
override fun subscribe(node: Any) {
|
||||
override fun subscribe(node: Any, parentId: Id?) {
|
||||
node as View
|
||||
nodeRef = WeakReference(node)
|
||||
|
||||
Log.i(LogTag, "Subscribing to decor view changes")
|
||||
|
||||
context.sharedThrottle.registerCallback(this.objectIdentity()) {
|
||||
nodeRef?.get()?.let { traverseAndSendWithSnapshot() }
|
||||
nodeRef?.get()?.let { traverseAndSendWithSnapshot(parentId) }
|
||||
}
|
||||
|
||||
preDrawListener =
|
||||
@@ -46,16 +47,21 @@ class DecorViewObserver(val context: UIDContext) : TreeObserver<DecorView>() {
|
||||
|
||||
// It can be the case that the DecorView the current observer owns has already
|
||||
// drawn. In this case, manually trigger an update.
|
||||
traverseAndSendWithSnapshot()
|
||||
traverseAndSendWithSnapshot(parentId)
|
||||
}
|
||||
|
||||
private fun traverseAndSendWithSnapshot() {
|
||||
private fun traverseAndSendWithSnapshot(parentId: Id?) {
|
||||
nodeRef?.get()?.let { view ->
|
||||
var snapshotBitmap: BitmapPool.ReusableBitmap? = null
|
||||
if (view.width > 0 && view.height > 0) {
|
||||
snapshotBitmap = context.bitmapPool.getBitmap(view.width, view.height)
|
||||
}
|
||||
traverseAndSend(context, view, snapshotBitmap)
|
||||
traverseAndSend(
|
||||
parentId,
|
||||
context,
|
||||
view,
|
||||
snapshotBitmap,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,35 +35,37 @@ abstract class TreeObserver<T> {
|
||||
|
||||
abstract val type: String
|
||||
|
||||
abstract fun subscribe(node: Any)
|
||||
abstract fun subscribe(node: Any, parentId: Id?)
|
||||
|
||||
abstract fun unsubscribe()
|
||||
|
||||
/** Traverses the layout hierarchy while managing any encountered child observers. */
|
||||
fun traverseAndSend(
|
||||
parentId: Id?,
|
||||
context: UIDContext,
|
||||
root: Any,
|
||||
snapshotBitmap: BitmapPool.ReusableBitmap? = null,
|
||||
frameworkEvents: List<FrameworkEvent>? = null
|
||||
) {
|
||||
val traversalStartTimestamp = System.currentTimeMillis()
|
||||
val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root)
|
||||
val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root, parentId)
|
||||
|
||||
// Add any new observers
|
||||
observableRoots.forEach { observable ->
|
||||
observableRoots.forEach { (observable, parentId) ->
|
||||
if (!children.containsKey(observable.objectIdentity())) {
|
||||
context.observerFactory.createObserver(observable, context)?.let { observer ->
|
||||
Log.d(
|
||||
LogTag,
|
||||
"Observer ${this.type} discovered new child of type ${observer.type} Node ID ${observable.objectIdentity()}")
|
||||
observer.subscribe(observable)
|
||||
observer.subscribe(observable, parentId)
|
||||
children[observable.objectIdentity()] = observer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove any old observers
|
||||
val observableRootsIdentifiers = observableRoots.map { it.objectIdentity() }
|
||||
val observableRootsIdentifiers =
|
||||
observableRoots.map { (observable, _) -> observable.objectIdentity() }
|
||||
val removables = mutableListOf<Id>()
|
||||
children.keys.forEach { key ->
|
||||
if (!observableRootsIdentifiers.contains(key)) {
|
||||
|
||||
@@ -78,7 +78,7 @@ class TreeObserverManager(val context: UIDContext) {
|
||||
mainScope.launch { start() }
|
||||
}
|
||||
batchedUpdates = Channel(Channel.UNLIMITED)
|
||||
rootObserver.subscribe(context.applicationRef)
|
||||
rootObserver.subscribe(context.applicationRef, null)
|
||||
|
||||
job =
|
||||
workerScope.launch {
|
||||
|
||||
@@ -31,14 +31,14 @@ class PartialLayoutTraversal(
|
||||
@Suppress("unchecked_cast")
|
||||
internal fun NodeDescriptor<*>.asAny(): NodeDescriptor<Any> = this as NodeDescriptor<Any>
|
||||
|
||||
fun traverse(root: Any): Pair<List<MaybeDeferred<Node>>, List<Any>> {
|
||||
fun traverse(root: Any, parentId: Id?): Pair<List<MaybeDeferred<Node>>, List<Pair<Any, Id?>>> {
|
||||
|
||||
val visited = mutableListOf<MaybeDeferred<Node>>()
|
||||
val observableRoots = mutableListOf<Any>()
|
||||
val observableRoots = mutableListOf<Pair<Any, Id?>>()
|
||||
|
||||
// cur and parent Id
|
||||
val stack = mutableListOf<Pair<Any, Id?>>()
|
||||
stack.add(Pair(root, null))
|
||||
stack.add(Pair(root, parentId))
|
||||
|
||||
val shallow = mutableSetOf<Any>()
|
||||
|
||||
@@ -48,7 +48,7 @@ class PartialLayoutTraversal(
|
||||
try {
|
||||
// If we encounter a node that has it own observer, don't traverse
|
||||
if (node != root && treeObserverFactory.hasObserverFor(node)) {
|
||||
observableRoots.add(node)
|
||||
observableRoots.add((node to parentId))
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user