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.ApplicationRef
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver
|
import com.facebook.flipper.plugins.uidebugger.core.RootViewResolver
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
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 com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,7 +24,7 @@ class ApplicationTreeObserver(val context: UIDContext) : TreeObserver<Applicatio
|
|||||||
|
|
||||||
override val type = "Application"
|
override val type = "Application"
|
||||||
|
|
||||||
override fun subscribe(node: Any) {
|
override fun subscribe(node: Any, parentId: Id?) {
|
||||||
Log.i(LogTag, "Subscribing activity / root view changes")
|
Log.i(LogTag, "Subscribing activity / root view changes")
|
||||||
|
|
||||||
val applicationRef = node as ApplicationRef
|
val applicationRef = node as ApplicationRef
|
||||||
@@ -41,7 +42,7 @@ class ApplicationTreeObserver(val context: UIDContext) : TreeObserver<Applicatio
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.sharedThrottle.registerCallback(this.objectIdentity()) {
|
context.sharedThrottle.registerCallback(this.objectIdentity()) {
|
||||||
traverseAndSend(context, applicationRef)
|
traverseAndSend(null, context, applicationRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
context.applicationRef.rootsResolver.attachListener(rootViewListener)
|
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.LogTag
|
||||||
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
import com.facebook.flipper.plugins.uidebugger.common.BitmapPool
|
||||||
import com.facebook.flipper.plugins.uidebugger.core.UIDContext
|
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 com.facebook.flipper.plugins.uidebugger.util.objectIdentity
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
@@ -26,14 +27,14 @@ class DecorViewObserver(val context: UIDContext) : TreeObserver<DecorView>() {
|
|||||||
|
|
||||||
override val type = "DecorView"
|
override val type = "DecorView"
|
||||||
|
|
||||||
override fun subscribe(node: Any) {
|
override fun subscribe(node: Any, parentId: Id?) {
|
||||||
node as View
|
node as View
|
||||||
nodeRef = WeakReference(node)
|
nodeRef = WeakReference(node)
|
||||||
|
|
||||||
Log.i(LogTag, "Subscribing to decor view changes")
|
Log.i(LogTag, "Subscribing to decor view changes")
|
||||||
|
|
||||||
context.sharedThrottle.registerCallback(this.objectIdentity()) {
|
context.sharedThrottle.registerCallback(this.objectIdentity()) {
|
||||||
nodeRef?.get()?.let { traverseAndSendWithSnapshot() }
|
nodeRef?.get()?.let { traverseAndSendWithSnapshot(parentId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
preDrawListener =
|
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
|
// It can be the case that the DecorView the current observer owns has already
|
||||||
// drawn. In this case, manually trigger an update.
|
// drawn. In this case, manually trigger an update.
|
||||||
traverseAndSendWithSnapshot()
|
traverseAndSendWithSnapshot(parentId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun traverseAndSendWithSnapshot() {
|
private fun traverseAndSendWithSnapshot(parentId: Id?) {
|
||||||
nodeRef?.get()?.let { view ->
|
nodeRef?.get()?.let { view ->
|
||||||
var snapshotBitmap: BitmapPool.ReusableBitmap? = null
|
var snapshotBitmap: BitmapPool.ReusableBitmap? = null
|
||||||
if (view.width > 0 && view.height > 0) {
|
if (view.width > 0 && view.height > 0) {
|
||||||
snapshotBitmap = context.bitmapPool.getBitmap(view.width, view.height)
|
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 val type: String
|
||||||
|
|
||||||
abstract fun subscribe(node: Any)
|
abstract fun subscribe(node: Any, parentId: Id?)
|
||||||
|
|
||||||
abstract fun unsubscribe()
|
abstract fun unsubscribe()
|
||||||
|
|
||||||
/** Traverses the layout hierarchy while managing any encountered child observers. */
|
/** Traverses the layout hierarchy while managing any encountered child observers. */
|
||||||
fun traverseAndSend(
|
fun traverseAndSend(
|
||||||
|
parentId: Id?,
|
||||||
context: UIDContext,
|
context: UIDContext,
|
||||||
root: Any,
|
root: Any,
|
||||||
snapshotBitmap: BitmapPool.ReusableBitmap? = null,
|
snapshotBitmap: BitmapPool.ReusableBitmap? = null,
|
||||||
frameworkEvents: List<FrameworkEvent>? = null
|
frameworkEvents: List<FrameworkEvent>? = null
|
||||||
) {
|
) {
|
||||||
val traversalStartTimestamp = System.currentTimeMillis()
|
val traversalStartTimestamp = System.currentTimeMillis()
|
||||||
val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root)
|
val (visitedNodes, observableRoots) = context.layoutTraversal.traverse(root, parentId)
|
||||||
|
|
||||||
// Add any new observers
|
// Add any new observers
|
||||||
observableRoots.forEach { observable ->
|
observableRoots.forEach { (observable, parentId) ->
|
||||||
if (!children.containsKey(observable.objectIdentity())) {
|
if (!children.containsKey(observable.objectIdentity())) {
|
||||||
context.observerFactory.createObserver(observable, context)?.let { observer ->
|
context.observerFactory.createObserver(observable, context)?.let { observer ->
|
||||||
Log.d(
|
Log.d(
|
||||||
LogTag,
|
LogTag,
|
||||||
"Observer ${this.type} discovered new child of type ${observer.type} Node ID ${observable.objectIdentity()}")
|
"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
|
children[observable.objectIdentity()] = observer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any old observers
|
// Remove any old observers
|
||||||
val observableRootsIdentifiers = observableRoots.map { it.objectIdentity() }
|
val observableRootsIdentifiers =
|
||||||
|
observableRoots.map { (observable, _) -> observable.objectIdentity() }
|
||||||
val removables = mutableListOf<Id>()
|
val removables = mutableListOf<Id>()
|
||||||
children.keys.forEach { key ->
|
children.keys.forEach { key ->
|
||||||
if (!observableRootsIdentifiers.contains(key)) {
|
if (!observableRootsIdentifiers.contains(key)) {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ class TreeObserverManager(val context: UIDContext) {
|
|||||||
mainScope.launch { start() }
|
mainScope.launch { start() }
|
||||||
}
|
}
|
||||||
batchedUpdates = Channel(Channel.UNLIMITED)
|
batchedUpdates = Channel(Channel.UNLIMITED)
|
||||||
rootObserver.subscribe(context.applicationRef)
|
rootObserver.subscribe(context.applicationRef, null)
|
||||||
|
|
||||||
job =
|
job =
|
||||||
workerScope.launch {
|
workerScope.launch {
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ class PartialLayoutTraversal(
|
|||||||
@Suppress("unchecked_cast")
|
@Suppress("unchecked_cast")
|
||||||
internal fun NodeDescriptor<*>.asAny(): NodeDescriptor<Any> = this as NodeDescriptor<Any>
|
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 visited = mutableListOf<MaybeDeferred<Node>>()
|
||||||
val observableRoots = mutableListOf<Any>()
|
val observableRoots = mutableListOf<Pair<Any, Id?>>()
|
||||||
|
|
||||||
// cur and parent Id
|
// cur and parent Id
|
||||||
val stack = mutableListOf<Pair<Any, Id?>>()
|
val stack = mutableListOf<Pair<Any, Id?>>()
|
||||||
stack.add(Pair(root, null))
|
stack.add(Pair(root, parentId))
|
||||||
|
|
||||||
val shallow = mutableSetOf<Any>()
|
val shallow = mutableSetOf<Any>()
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ class PartialLayoutTraversal(
|
|||||||
try {
|
try {
|
||||||
// If we encounter a node that has it own observer, don't traverse
|
// If we encounter a node that has it own observer, don't traverse
|
||||||
if (node != root && treeObserverFactory.hasObserverFor(node)) {
|
if (node != root && treeObserverFactory.hasObserverFor(node)) {
|
||||||
observableRoots.add(node)
|
observableRoots.add((node to parentId))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user