I'm trying to scrape visible elements on Android via the Accessibility Service. I wish to store the element's details into an array to be processed later and all at the same time.
This particular loop is used to find the element's parents, their children, and their children's children. It can spawn 30 loops, iterating over itself until the lowest child is found. Say if I have another thread waiting to process that complete array, how would it know when the array is ready?
This is a situation of no hard coded variables. There are no size references nor any other obvious ending signatures I can think of to use. I've tried counting repeats and null children, but it's either not accurate or inconclusive.
Thank you,
public void nodeToArray(int id, AccessibilityNodeInfo node) {
final String TCLASS = "nodeToArray";
int count = node.getChildCount();
for (int i = 0; i < count; i ) {
AccessibilityNodeInfo child = node.getChild(i);
if (child != null) {
if (child.isVisibleToUser()) {
ArrayList<String> childAttrs = new ArrayList<>();
if ( child.getPackageName() != null ) { childAttrs.add( child.getPackageName().toString().trim() ); } else { childAttrs.add(""); } //package
if ( child.getClassName() != null ) { childAttrs.add( child.getClassName().toString().trim() ); } else { childAttrs.add(""); } //class
if ( child.getViewIdResourceName() != null ) { childAttrs.add( child.getViewIdResourceName().trim() ); } else { childAttrs.add(""); } //id
if ( child.getText() != null ) { childAttrs.add( child.getText().toString().trim() ); } else { childAttrs.add(""); } //text
if ( child.getContentDescription() != null ) { childAttrs.add( child.getContentDescription().toString().trim() ); } else { childAttrs.add(""); } //desc
Rect r = new Rect();
child.getBoundsInScreen(r);
childAttrs.add( r.left "/" r.top "/" r.right "/" r.bottom ); //bounds
//
if ( queryMap.size() == 0 ) {
queryMap.put( 0, childAttrs );
} else {
queryMap.put( queryMap.size(), childAttrs );
}
//
nodeToArray(id, child);
child.recycle();
}
}
}
CommonUtils.Echo("ScreenStater", TCLASS, "id:" id " - size:" queryMap.size(), 1);
}
2021-09-22 17:39:43.187 27601-27786/com.example.accessibility_test I/ScreenStater-processArray: processing:23
2021-09-22 17:39:43.247 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:8
2021-09-22 17:39:43.248 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:9
2021-09-22 17:39:43.248 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:11
2021-09-22 17:39:43.248 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:12
2021-09-22 17:39:43.248 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:12
2021-09-22 17:39:43.248 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:18
2021-09-22 17:39:43.248 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:19
2021-09-22 17:39:43.249 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:19
2021-09-22 17:39:43.249 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:20
2021-09-22 17:39:43.249 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:21
2021-09-22 17:39:43.249 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:22
2021-09-22 17:39:43.249 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:23
2021-09-22 17:39:43.249 27601-27601/com.example.accessibility_test I/ScreenStater-nodeToArray: id:788 - size:23
CodePudding user response:
You need some method of actual interthread communication.
The code you show is eventually going to produce something, the array. The other thread needs to (a) wait, and (b) receive the array.
There are several Future mechanisms in Java to support this sort of usage. I'd suggest CompletableFuture as a good example.
Whatever starts this mechanism creates a CompletableFuture and makes it available to producer and eventual consumer. The producer will 'complete' the future when it is done, and the consumer will wait (or otherwise arrange to get notification) on the completion.
Since nodeToArray is (synchronously) recursive, you'd complete the Future only at the topmost level.