簡體   English   中英

在 WebView 上為 evaluateJavascript function 創建隊列

[英]Creating a queue for the evaluateJavascript function on a WebView

我有一個混合應用程序,我的一些活動使用 WebView 來顯示 web 內容。 我在 WebView 中展示的 web 應用程序有一個 JS 接口,可以讓我向 web 應用程序發送命令以導航到不同的地方或做不同的事情。

例如,如果我需要我的 web 應用程序導航到“用戶配置文件”頁面,我執行如下命令:

class SomeActivity: AppCompatActivity {
   ...
   webView.evaluateJavascript("navigateTo(\"userprofile\")")
   ...
}

然后通過 JS 界面,我得到一個響應,應用程序做出相應的反應。

為了提高性能,我引入了一個 JS 隊列,因此 JS 命令是按順序執行的。 我沒有直接在 WebView 上調用evaluateJavascript() function,而是創建了一個自定義 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)
        }
    }
}
  • 如何預處理Channel<String>中的 js 命令,以便放棄重復的 js 命令?
  • 此外,有時我的 WebView 會變得不可見,我想在發生這種情況時暫停隊列。 我想知道是否有任何方法可以以編程方式暫停Channel

編輯#1

此外,有時我的 WebView 會變得不可見,我想在發生這種情況時暫停隊列。 我想知道是否有任何方法可以以編程方式暫停Channel

我試過使用這個PausableDispatcher實現,它似乎在做這個伎倆。

您提供的所有命令示例都遵循特定模式:它們都是函數。 我們可以利用這個優勢!

首先,讓我們創建一些術語。

navigateTo()是一個 function (當然。)。 讓我們將 function 的navigateTo部分稱為type

一些type的例子是:

console.log() => `console.log`,
gotoUrl(url) => `gotoUrl`.

我只是編造了這個術語。 但它會幫助你理解邏輯。

現在,我們需要做的是查看命令數組,了解它的type ,並檢查是否有其他命令具有相同的類型。 如果是這樣,則需要在執行隊列之前將它們從隊列中排除。

簡單的!

我編寫了一個示例代碼,您可以將其與您的腳本集成:

// 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())

如果我錯過了回答這個問題的分數,請告訴我。 否則,為一個偉大的隊列系統干杯!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM