fix: 限制节点数量避免内存溢出

This commit is contained in:
lisonge 2023-10-08 11:51:26 +08:00
parent c029a38bb8
commit 8074175489
3 changed files with 72 additions and 43 deletions

View File

@ -96,47 +96,74 @@ private fun AccessibilityNodeInfo.getTempRect(): Rect {
return tempRect return tempRect
} }
val abTransform = Transform<AccessibilityNodeInfo>(
getAttr = { node, name ->
when (name) {
"id" -> node.viewIdResourceName
"name" -> node.className
"text" -> node.text
"text.length" -> node.text?.length
"desc" -> node.contentDescription
"desc.length" -> node.contentDescription?.length
"clickable" -> node.isClickable // https://github.com/gkd-kit/gkd/issues/115
"checkable" -> node.isCheckable private const val MAX_CHILD_SIZE = 256
"checked" -> node.isChecked private const val MAX_DESCENDANTS_SIZE = 4096
"focusable" -> node.isFocusable
"visibleToUser" -> node.isVisibleToUser
"left" -> node.getTempRect().left private val getChildren: (AccessibilityNodeInfo) -> Sequence<AccessibilityNodeInfo> = { node ->
"top" -> node.getTempRect().top sequence {
"right" -> node.getTempRect().right repeat(node.childCount.coerceAtMost(MAX_CHILD_SIZE)) { i ->
"bottom" -> node.getTempRect().bottom val child = node.getChild(i) ?: return@sequence
yield(child)
"width" -> node.getTempRect().width()
"height" -> node.getTempRect().height()
"index" -> node.getIndex()
"depth" -> node.getDepth()
"childCount" -> node.childCount
else -> null
} }
}, }
}
private val getAttr: (AccessibilityNodeInfo, String) -> Any? = { node, name ->
when (name) {
"id" -> node.viewIdResourceName
"name" -> node.className
"text" -> node.text
"text.length" -> node.text?.length
"desc" -> node.contentDescription
"desc.length" -> node.contentDescription?.length
"clickable" -> node.isClickable
"checkable" -> node.isCheckable
"checked" -> node.isChecked
"focusable" -> node.isFocusable
"visibleToUser" -> node.isVisibleToUser
"left" -> node.getTempRect().left
"top" -> node.getTempRect().top
"right" -> node.getTempRect().right
"bottom" -> node.getTempRect().bottom
"width" -> node.getTempRect().width()
"height" -> node.getTempRect().height()
"index" -> node.getIndex()
"depth" -> node.getDepth()
"childCount" -> node.childCount
else -> null
}
}
val abTransform = Transform(getAttr = getAttr,
getName = { node -> node.className }, getName = { node -> node.className },
getChildren = { node -> getChildren = getChildren,
sequence {
repeat(node.childCount) { i ->
yield(node.getChild(i))
}
}
},
getChild = { node, index -> node.getChild(index) }, getChild = { node, index -> node.getChild(index) },
getParent = { node -> node.parent }, getParent = { node -> node.parent },
) getDescendants = { node ->
sequence {
val stack = mutableListOf(node)
val tempNodes = mutableListOf<AccessibilityNodeInfo>()
do {
val top = stack.removeLast()
yield(top)
for (childNode in getChildren(top)) {
tempNodes.add(childNode)
}
if (tempNodes.isNotEmpty()) {
for (i in tempNodes.size - 1 downTo 0) {
stack.add(tempNodes[i])
}
tempNodes.clear()
}
} while (stack.isNotEmpty())
}.take(MAX_DESCENDANTS_SIZE)
})
private var lastToastTime = -1L private var lastToastTime = -1L
fun toastClickTip() { fun toastClickTip() {

View File

@ -8,7 +8,7 @@ import kotlin.js.JsExport
class CommonTransform<T : Any>( class CommonTransform<T : Any>(
getAttr: (T, String) -> Any?, getAttr: (T, String) -> Any?,
getName: (T) -> String?, getName: (T) -> String?,
getChildren: (T) -> Array<T?>, getChildren: (T) -> Array<T>,
getParent: (T) -> T?, getParent: (T) -> T?,
) { ) {
internal val transform = Transform( internal val transform = Transform(
@ -18,26 +18,27 @@ class CommonTransform<T : Any>(
getParent = getParent, getParent = getParent,
) )
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST", "UNUSED")
val querySelectorAll: (T, CommonSelector) -> Array<T> = { node, selector -> val querySelectorAll: (T, CommonSelector) -> Array<T> = { node, selector ->
val result = val result =
transform.querySelectorAll(node, selector.selector).toList().toTypedArray<Any?>() transform.querySelectorAll(node, selector.selector).toList().toTypedArray<Any?>()
result as Array<T> result as Array<T>
} }
@Suppress("UNUSED")
val querySelector: (T, CommonSelector) -> T? = { node, selector -> val querySelector: (T, CommonSelector) -> T? = { node, selector ->
transform.querySelectorAll(node, selector.selector).firstOrNull() transform.querySelectorAll(node, selector.selector).firstOrNull()
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST", "UNUSED")
val querySelectorTrackAll: (T, CommonSelector) -> Array<Array<T>> = { node, selector -> val querySelectorTrackAll: (T, CommonSelector) -> Array<Array<T>> = { node, selector ->
val result = transform.querySelectorTrackAll(node, selector.selector) val result = transform.querySelectorTrackAll(node, selector.selector)
.map { it.toTypedArray<Any?>() as Array<T> }.toList().toTypedArray<Any?>() .map { it.toTypedArray<Any?>() as Array<T> }.toList().toTypedArray<Any?>()
result as Array<Array<T>> result as Array<Array<T>>
} }
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST", "UNUSED")
val querySelectorTrack: (T, CommonSelector) -> Array<T>? = { node, selector -> val querySelectorTrack: (T, CommonSelector) -> Array<T>? = { node, selector ->
transform.querySelectorTrackAll(node, selector.selector).firstOrNull() transform.querySelectorTrackAll(node, selector.selector).firstOrNull()
?.toTypedArray<Any?>() as Array<T>? ?.toTypedArray<Any?>() as Array<T>?

View File

@ -4,7 +4,7 @@ package li.songe.selector
class Transform<T>( class Transform<T>(
val getAttr: (T, String) -> Any?, val getAttr: (T, String) -> Any?,
val getName: (T) -> CharSequence?, val getName: (T) -> CharSequence?,
val getChildren: (T) -> Sequence<T?>, val getChildren: (T) -> Sequence<T>,
val getChild: (T, Int) -> T? = { node, offset -> getChildren(node).elementAtOrNull(offset) }, val getChild: (T, Int) -> T? = { node, offset -> getChildren(node).elementAtOrNull(offset) },
val getParent: (T) -> T?, val getParent: (T) -> T?,
val getAncestors: (T) -> Sequence<T> = { node -> val getAncestors: (T) -> Sequence<T> = { node ->
@ -55,9 +55,7 @@ class Transform<T>(
val top = stack.removeLast() val top = stack.removeLast()
yield(top) yield(top)
for (childNode in getChildren(top)) { for (childNode in getChildren(top)) {
if (childNode != null) { tempNodes.add(childNode)
tempNodes.add(childNode)
}
} }
if (tempNodes.isNotEmpty()) { if (tempNodes.isNotEmpty()) {
for (i in tempNodes.size - 1 downTo 0) { for (i in tempNodes.size - 1 downTo 0) {
@ -70,6 +68,7 @@ class Transform<T>(
}, },
) { ) {
val querySelectorAll: (T, Selector) -> Sequence<T> = { node, selector -> val querySelectorAll: (T, Selector) -> Sequence<T> = { node, selector ->
sequence { sequence {
val trackNodes: MutableList<T> = mutableListOf() val trackNodes: MutableList<T> = mutableListOf()
@ -95,6 +94,8 @@ class Transform<T>(
} }
} }
} }
@Suppress("UNUSED")
val querySelectorTrack: (T, Selector) -> List<T>? = { node, selector -> val querySelectorTrack: (T, Selector) -> List<T>? = { node, selector ->
querySelectorTrackAll( querySelectorTrackAll(
node, selector node, selector