Создание очереди для функции AssessmentJavascript в WebView
У меня гибридное приложение, некоторые из моих действий используют WebView для отображения веб-контента. Веб-приложение, которое я показываю в WebView, имеет интерфейс JS, который позволяет мне отправлять команды веб-приложению для перехода в разные места или выполнения разных действий.
Например, если мне нужно, чтобы мое веб-приложение переходило на страницу «профиля пользователя», я выполняю такую команду, как:
class SomeActivity: AppCompatActivity {
...
webView.evaluateJavascript("navigateTo(\"userprofile\")")
...
}
Затем через интерфейс JS я получаю ответ, и приложение реагирует соответствующим образом.
Для повышения производительности я ввел очередь JS, поэтому команды JS выполняются последовательно. Вместо того, чтобы позвонить
evaluateJavascript()
функция непосредственно в WebView. Я создал пользовательский компонент WebView с этой очередью JS, установленной в качестве свойства.
class SomeActivity: AppCompatActivity {
...
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"userprofile\")")
...
}
Теперь я хотел бы добавить к этому новое поведение, а именно возможность предварительно обрабатывать команды в очереди. Под предварительной обработкой я подразумеваю то, что если я когда-либо ставлю в очередь команды одного и того же «типа», например:
class SomeActivity: AppCompatActivity {
...
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"userprofile\")")
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"about-me\")")
webView.jsQueue.queueEvaluateJavascript("navigateTo(\"user-list\")")
...
}
Я бы хотел, чтобы очередь была достаточно умной, чтобы отбросить эти две первые команды «навигации» -
"navigateTo(\"userprofile\")"
и
"navigateTo(\"about-me\")"
- потому что я не хочу, чтобы мой WebView переходил в эти два места только для того, чтобы наконец перейти к
"navigateTo(\"user-list\")"
.
Реализация этой очереди JS выглядит так:
class JsQueue(
private val webView: WebView,
private val scope: CoroutineScope
) {
init {
scope.launch {
for (jsScript in jsChannel) {
runJs(jsScript)
}
}
}
private val jsChannel = Channel<String>(BUFFERED)
fun queueEvaluateJavascript(script: String) {
runBlocking {
jsChannel.send(script)
}
}
suspend fun runJs(script: String) = suspendCoroutine<String> { cont ->
webView.evaluateJavascript(script) { result ->
cont.resume(result)
}
}
}
- Как я могу предварительно обработать команды js в
Channel<String>
так я избавляюсь от дублированных команд js? - Кроме того, иногда мой WebView становится невидимым, и я хочу приостановить очередь, когда это произойдет. Мне интересно, есть ли способ программно приостановить канал ?
Редактировать # 1
Кроме того, иногда мой WebView становится невидимым, и я хочу приостановить очередь, когда это произойдет. Мне интересно, есть ли способ программно приостановить канал ?
Я пробовал использовать это
PausableDispatcher
реализация, и кажется, что это помогает.
1 ответ
Все приведенные вами примеры команд следуют определенному шаблону: все они являются функциями. Мы можем использовать это в своих интересах!
Во-первых, давайте создадим некоторую терминологию.
Примером некоторых s являются:
console.log() => `console.log`,
gotoUrl(url) => `gotoUrl`.
Я просто придумал эту терминологию. Но это поможет вам понять логику.
Теперь, что нам нужно сделать, это посмотреть на массив команд, понять его
Легкий!
Я написал пример кода, который вы можете интегрировать со своим скриптом:
// Example array of commands for demonstration.
let commands = [
'navigateTo("a")',
'navigateTo("b")',
'navigateTo("c")',
];
/** A list of non-duplicate types*/
let types = [];
/** A list of non-duplicate commands */
let newCommands = [];
// Reverse the array because the most important commands start from the end of array.
for(let command of commands.reverse()){
let type = command.slice(0, command.indexOf('('));
// Determine if type already exists
let alreadyExists = false;
for(let commandType of types){
if(type == commandType){
alreadyExists = true;
break;
}
}
if(alreadyExists)
// Type already exists. Do not add to command list.
continue;
// This type & command does not exist.
// Update command & type arrays
types.push(type);
newCommands.push(command)
}
// New Commands
console.log("Commands: ", newCommands);
// If you want to keep same queue order without duplicates:
console.log("Commands: ", newCommands.reverse())
Дайте мне знать, если я пропустил ответ на этот вопрос. В противном случае, ура отличной системе очередей!