Я разрабатываю службу автоматизации на Kotlin, которая использует root-доступ и uiautomator для обнаружения значений на экране устройства Android. Однако поиск значения занимает около 3 секунд, что слишком медленно для требуемого функционала. Целевое значение отображается на экране, но оно не обнаруживается так быстро, как ожидалось.
Кроме того, я использую тестовое приложение, которое меняет значения на экране каждые 5 секунд, поэтому мне нужно чтобы обнаруживать значения как можно быстрее.
Я использовал root-доступ и uiautomator для получения значений с экрана, но столкнулся с проблемами производительности, особенно со скоростью. Обнаружение происходит медленнее, чем мне нужно. Я пытался оптимизировать поток выполнения, но не нашел решения, отвечающего требуемой скорости.
Я ищу способы ускорить этот процесс обнаружения, желательно без использования служб доступности. . Если есть какие-либо оптимизации или другие подходы, которые я могу попробовать, я буду признателен за ваши предложения.
Журналы
2025 г. -01-03 23:30:19.234 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:19.234 32522-893 SearchService com.lr D Установленное целевое значение: 160
03.01.2025 23:30:21.560 32522-893 SearchService com.lr D ===== ЗАВЕРШЕНИЕ ПОИСКА ЗНАЧЕНИЙ == ===
03.01.2025 23:30:21.560 32522-893 SearchService com.lr D Всего проанализировано значений: 4
03.01.2025 23:30:21.560 32522-893 SearchService com.lr D Всего найдено значений: 0
2025 -01-03 23:30:21.760 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:21.760 32522-893 SearchService com.lr D Установленное целевое значение: 160
2025-01-03 23:30:24.058 32522-893 SearchService com.lr D ===== ЗАВЕРШЕНИЕ ПОИСКА ЗНАЧЕНИЙ =====
2025-01-03 23:30:24.058 32522-893 SearchService com.lr D Всего проанализировано значений: 4
2025-01-03 23:30:24.059 32522-893 SearchService com.lr D Всего найдено значений: 0
2025-01-03 23:30:24.216 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:24.216 32522-893 SearchService com.lr D Установленное целевое значение: 160
2025-01-03 23:30:26.533 32522-893 SearchService com.lr D ===== ЗАВЕРШАЮЩИЙ ПОИСК ЗНАЧЕНИЙ =====
2025-01-03 23:30:26.533 32522-893 SearchService com.lr D Всего проанализировано значений: 0
03.01.2025 23:30:26.533 32522-893 SearchService com.lr D Всего найдено значений: 0
03.01.2025 23 :30:26.722 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:26.722 32522-893 SearchService com.lr D Установленное целевое значение: 160
2025-01-03 23 :30:29.905 32522-893 SearchService com.lr D >>> Значение Найдено больше или равно: $165 (числовое значение: 165 >= 160)
2025-01-03 23:30:29.905 32522-893 SearchService com.lr D >>> Значение добавлено в список с границами: Rect( 36, 376 - 167, 479)
03.01.2025 23:30:29.908 32522-893 SearchService com.lr D >>> Значение, добавленное в хранилище
**Код, вызывающий проблему**
class SearchService {
companion object {
private const val TAG = "SearchService"
private val NODE_REGEX = "]*text=\"\\$[^\"]*\"[^>]*bounds=\"\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]\"[^>]*/>".toRegex()
private val TEXT_REGEX = "text=\"(\\$[^\"]+)\"".toRegex()
private val NUMBER_REGEX = "\\$(\\d+)".toRegex()
private val BOUNDS_REGEX = "bounds=\"\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]\"[^>]*/>".toRegex()
}
fun getCurrentPackageName(): String? {
val output = executeRootCommand("dumpsys window | grep mCurrentFocus")
return try {
val regex = "\\{.*?\\s+(\\S+)/".toRegex()
val matchResult = regex.find(output)
val packageName = matchResult?.groupValues?.get(1)
Log.d(TAG, "Extracted package name: $packageName from output: $output")
packageName
} catch (e: Exception) {
Log.e(TAG, "Error extracting package name: ${e.message}")
null
}
}
suspend fun searchForValues(targetValue: String, searching: AtomicBoolean): List {
if (!searching.get()) {
Log.d(TAG, "Search already completed earlier, ignoring call")
return emptyList()
}
return withContext(Dispatchers.IO) {
try {
val startTime = System.currentTimeMillis()
Log.d(TAG, "\n----------------------------------------")
Log.d(TAG, "===== STARTING VALUE SEARCH =====")
Log.d(TAG, "Target value set: $targetValue")
if (targetValue.isEmpty()) {
Log.e(TAG, "ERROR: Target value not set!")
return@withContext emptyList()
}
val targetValueInt = targetValue.toIntOrNull() ?: run {
Log.e(TAG, "ERROR: Target value is not a valid number!")
return@withContext emptyList()
}
val values = mutableListOf()
var totalValuesAnalyzed = 0
Log.d(TAG, "Checking UiAutomator availability...")
val uiautomatorPath = executeRootCommand("which uiautomator") ?: ""
if (uiautomatorPath.isBlank()) {
Log.e(TAG, "UiAutomator not found!")
return@withContext emptyList()
}
executeRootCommand("chmod 777 /sdcard")
val dumpCommand = "uiautomator dump /sdcard/window_dump.xml && cat /sdcard/window_dump.xml"
Log.d(TAG, "Executing UiAutomator command: $dumpCommand")
val xmlOutput = executeRootCommand(dumpCommand) ?: ""
if (xmlOutput.isBlank()) {
Log.e(TAG, "No output from UiAutomator!")
return@withContext emptyList()
}
val matches = NODE_REGEX.findAll(xmlOutput)
matches.forEach { match ->
try {
val fullText = TEXT_REGEX.find(match.value)?.groupValues?.get(1)
if (fullText != null) {
totalValuesAnalyzed++
val foundNumber = NUMBER_REGEX.find(fullText)?.groupValues?.get(1)?.toIntOrNull()
if (foundNumber != null && foundNumber >= targetValueInt) {
val boundsMatch = BOUNDS_REGEX.find(match.value)
if (boundsMatch != null) {
val (left, top, right, bottom) = boundsMatch.destructured
val bounds = Rect(
left.toInt(),
top.toInt(),
right.toInt(),
bottom.toInt()
)
val result = Pair(fullText, bounds)
values.add(result)
Log.d(TAG, ">>> Value greater or equal found: $fullText (numeric value: $foundNumber >= $targetValueInt)")
Log.d(TAG, ">>> Value added to list with bounds: $bounds")
Store.get().add(Item(
txt = fullText,
time = System.currentTimeMillis(),
area = bounds
))
Log.d(TAG, ">>> Value added to Store")
}
}
}
} catch (e: Exception) {
Log.e(TAG, "Error processing node: ${e.message}")
}
}
executeRootCommand("rm /sdcard/window_dump.xml")
val endTime = System.currentTimeMillis()
Log.d(TAG, "\n----------------------------------------")
Log.d(TAG, "===== FINISHING VALUE SEARCH =====")
Log.d(TAG, "Total values analyzed: $totalValuesAnalyzed")
Log.d(TAG, "Total values found: ${values.size}")
Log.d(TAG, "Total search time: ${endTime - startTime} ms")
Log.d(TAG, "----------------------------------------\n")
values
} catch (e: Exception) {
Log.e(TAG, "===== ERROR IN VALUE SEARCH =====")
Log.e(TAG, "Error: ${e.message}")
Log.e(TAG, "Stack trace: ${e.stackTrace.joinToString("\n")}")
emptyList()
}
}
}
fun executeRootCommand(command: String): String {
return try {
val process = Runtime.getRuntime().exec("su")
val outputStream = DataOutputStream(process.outputStream)
Log.d(TAG, "Executing root command: $command")
outputStream.writeBytes("$command\n")
outputStream.flush()
outputStream.writeBytes("exit\n")
outputStream.flush()
outputStream.close()
val reader = BufferedReader(InputStreamReader(process.inputStream))
val output = StringBuilder()
var line: String?
while (reader.readLine().also { line = it } != null) {
output.append(line).append("\n")
}
val result = output.toString().trim()
Log.d(TAG, "Root command output: $result")
process.waitFor()
process.destroy()
result
} catch (e: Exception) {
Log.e(TAG, "Root command error: ${e.message}")
""
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... lin-optimi
Медленное обнаружение значений экрана с использованием root-доступа и uiautomator в Kotlin. Требуется помощь по оптимиза ⇐ Android
Форум для тех, кто программирует под Android
1736026509
Anonymous
Я разрабатываю службу автоматизации на Kotlin, которая использует root-доступ и uiautomator для обнаружения значений на экране устройства Android. Однако поиск значения занимает около 3 секунд, что слишком медленно для требуемого функционала. Целевое значение отображается на экране, но оно не обнаруживается так быстро, как ожидалось.
Кроме того, я использую тестовое приложение, которое меняет значения на экране каждые 5 секунд, поэтому мне нужно чтобы обнаруживать значения как можно быстрее.
Я использовал root-доступ и uiautomator для получения значений с экрана, но столкнулся с проблемами производительности, особенно со скоростью. Обнаружение происходит медленнее, чем мне нужно. Я пытался оптимизировать поток выполнения, но не нашел решения, отвечающего требуемой скорости.
Я ищу способы ускорить этот процесс обнаружения, желательно без использования служб доступности. . Если есть какие-либо оптимизации или другие подходы, которые я могу попробовать, я буду признателен за ваши предложения.
[b]Журналы[/b]
2025 г. -01-03 23:30:19.234 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:19.234 32522-893 SearchService com.lr D Установленное целевое значение: 160
03.01.2025 23:30:21.560 32522-893 SearchService com.lr D ===== ЗАВЕРШЕНИЕ ПОИСКА ЗНАЧЕНИЙ == ===
03.01.2025 23:30:21.560 32522-893 SearchService com.lr D Всего проанализировано значений: 4
03.01.2025 23:30:21.560 32522-893 SearchService com.lr D Всего найдено значений: 0
2025 -01-03 23:30:21.760 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:21.760 32522-893 SearchService com.lr D Установленное целевое значение: 160
2025-01-03 23:30:24.058 32522-893 SearchService com.lr D ===== ЗАВЕРШЕНИЕ ПОИСКА ЗНАЧЕНИЙ =====
2025-01-03 23:30:24.058 32522-893 SearchService com.lr D Всего проанализировано значений: 4
2025-01-03 23:30:24.059 32522-893 SearchService com.lr D Всего найдено значений: 0
2025-01-03 23:30:24.216 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:24.216 32522-893 SearchService com.lr D Установленное целевое значение: 160
2025-01-03 23:30:26.533 32522-893 SearchService com.lr D ===== ЗАВЕРШАЮЩИЙ ПОИСК ЗНАЧЕНИЙ =====
2025-01-03 23:30:26.533 32522-893 SearchService com.lr D Всего проанализировано значений: 0
03.01.2025 23:30:26.533 32522-893 SearchService com.lr D Всего найдено значений: 0
03.01.2025 23 :30:26.722 32522-893 SearchService com.lr D ===== ПОИСК НАЧАЛЬНОГО ЗНАЧЕНИЯ =====
2025-01-03 23:30:26.722 32522-893 SearchService com.lr D Установленное целевое значение: 160
2025-01-03 23 :30:29.905 32522-893 SearchService com.lr D >>> Значение Найдено больше или равно: $165 (числовое значение: 165 >= 160)
2025-01-03 23:30:29.905 32522-893 SearchService com.lr D >>> Значение добавлено в список с границами: Rect( 36, 376 - 167, 479)
03.01.2025 23:30:29.908 32522-893 SearchService com.lr D >>> Значение, добавленное в хранилище
**Код, вызывающий проблему**
class SearchService {
companion object {
private const val TAG = "SearchService"
private val NODE_REGEX = "]*text=\"\\$[^\"]*\"[^>]*bounds=\"\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]\"[^>]*/>".toRegex()
private val TEXT_REGEX = "text=\"(\\$[^\"]+)\"".toRegex()
private val NUMBER_REGEX = "\\$(\\d+)".toRegex()
private val BOUNDS_REGEX = "bounds=\"\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]\"[^>]*/>".toRegex()
}
fun getCurrentPackageName(): String? {
val output = executeRootCommand("dumpsys window | grep mCurrentFocus")
return try {
val regex = "\\{.*?\\s+(\\S+)/".toRegex()
val matchResult = regex.find(output)
val packageName = matchResult?.groupValues?.get(1)
Log.d(TAG, "Extracted package name: $packageName from output: $output")
packageName
} catch (e: Exception) {
Log.e(TAG, "Error extracting package name: ${e.message}")
null
}
}
suspend fun searchForValues(targetValue: String, searching: AtomicBoolean): List {
if (!searching.get()) {
Log.d(TAG, "Search already completed earlier, ignoring call")
return emptyList()
}
return withContext(Dispatchers.IO) {
try {
val startTime = System.currentTimeMillis()
Log.d(TAG, "\n----------------------------------------")
Log.d(TAG, "===== STARTING VALUE SEARCH =====")
Log.d(TAG, "Target value set: $targetValue")
if (targetValue.isEmpty()) {
Log.e(TAG, "ERROR: Target value not set!")
return@withContext emptyList()
}
val targetValueInt = targetValue.toIntOrNull() ?: run {
Log.e(TAG, "ERROR: Target value is not a valid number!")
return@withContext emptyList()
}
val values = mutableListOf()
var totalValuesAnalyzed = 0
Log.d(TAG, "Checking UiAutomator availability...")
val uiautomatorPath = executeRootCommand("which uiautomator") ?: ""
if (uiautomatorPath.isBlank()) {
Log.e(TAG, "UiAutomator not found!")
return@withContext emptyList()
}
executeRootCommand("chmod 777 /sdcard")
val dumpCommand = "uiautomator dump /sdcard/window_dump.xml && cat /sdcard/window_dump.xml"
Log.d(TAG, "Executing UiAutomator command: $dumpCommand")
val xmlOutput = executeRootCommand(dumpCommand) ?: ""
if (xmlOutput.isBlank()) {
Log.e(TAG, "No output from UiAutomator!")
return@withContext emptyList()
}
val matches = NODE_REGEX.findAll(xmlOutput)
matches.forEach { match ->
try {
val fullText = TEXT_REGEX.find(match.value)?.groupValues?.get(1)
if (fullText != null) {
totalValuesAnalyzed++
val foundNumber = NUMBER_REGEX.find(fullText)?.groupValues?.get(1)?.toIntOrNull()
if (foundNumber != null && foundNumber >= targetValueInt) {
val boundsMatch = BOUNDS_REGEX.find(match.value)
if (boundsMatch != null) {
val (left, top, right, bottom) = boundsMatch.destructured
val bounds = Rect(
left.toInt(),
top.toInt(),
right.toInt(),
bottom.toInt()
)
val result = Pair(fullText, bounds)
values.add(result)
Log.d(TAG, ">>> Value greater or equal found: $fullText (numeric value: $foundNumber >= $targetValueInt)")
Log.d(TAG, ">>> Value added to list with bounds: $bounds")
Store.get().add(Item(
txt = fullText,
time = System.currentTimeMillis(),
area = bounds
))
Log.d(TAG, ">>> Value added to Store")
}
}
}
} catch (e: Exception) {
Log.e(TAG, "Error processing node: ${e.message}")
}
}
executeRootCommand("rm /sdcard/window_dump.xml")
val endTime = System.currentTimeMillis()
Log.d(TAG, "\n----------------------------------------")
Log.d(TAG, "===== FINISHING VALUE SEARCH =====")
Log.d(TAG, "Total values analyzed: $totalValuesAnalyzed")
Log.d(TAG, "Total values found: ${values.size}")
Log.d(TAG, "Total search time: ${endTime - startTime} ms")
Log.d(TAG, "----------------------------------------\n")
values
} catch (e: Exception) {
Log.e(TAG, "===== ERROR IN VALUE SEARCH =====")
Log.e(TAG, "Error: ${e.message}")
Log.e(TAG, "Stack trace: ${e.stackTrace.joinToString("\n")}")
emptyList()
}
}
}
fun executeRootCommand(command: String): String {
return try {
val process = Runtime.getRuntime().exec("su")
val outputStream = DataOutputStream(process.outputStream)
Log.d(TAG, "Executing root command: $command")
outputStream.writeBytes("$command\n")
outputStream.flush()
outputStream.writeBytes("exit\n")
outputStream.flush()
outputStream.close()
val reader = BufferedReader(InputStreamReader(process.inputStream))
val output = StringBuilder()
var line: String?
while (reader.readLine().also { line = it } != null) {
output.append(line).append("\n")
}
val result = output.toString().trim()
Log.d(TAG, "Root command output: $result")
process.waitFor()
process.destroy()
result
} catch (e: Exception) {
Log.e(TAG, "Root command error: ${e.message}")
""
}
}
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79329650/slow-screen-value-detection-using-root-access-and-uiautomator-in-kotlin-optimi[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия