【问题标题】:How to force Android-WebView to Redraw/Re-Render immediately?如何强制 Android-WebView 立即重绘/重新渲染?
【发布时间】:2021-05-28 18:28:19
【问题描述】:

基本上JavascriptInterface 收到来自WebView 的 Click 事件,然后我需要多次更改 HTML 元素,问题是 WebView 只显示最后一次更改,这意味着渲染不是立即的。

问题:如何让webview.loadUrl("javascript:updateProgress(20);");立即生效并更改WebView内容?

- - - - - - - - - - - - - - - -

老问题:

我的 WebView 中有一个 HTML 进度条,我可以通过运行 webview.loadUrl("javascript:updateProgress(20);"); 来简单地更新进度条值,这可以从 onCreate() 正常工作。

// JavaScript in WebView
function updateProgress(percentage){

    document.getElementById('progressBar').style.width = percentage + '%';
}

现在,我有一个将二进制数据发送到连接的 BLE 设备的类,我从 Google BluetoothLeGatt 中获取示例,并添加了一个方法来写入 BluetoothLeService.java 中的特征(发送数据)。

public void WriteCharacteristic(BluetoothGattCharacteristic characteristic, byte[] data, MainActivity mainactivity){

    byte[] data_twenty_byte = new byte [20];
    int progress_count = 0;

    while(get_next_twenty_byte(data, data_twenty_byte)){

        characteristic.setValue(data_twenty_byte);
        mBluetoothGatt.writeCharacteristic(characteristic);

        progress_count++;
        mainactivity.webview.loadUrl("javascript:updateProgress(" + progress_count + ");");
    }
}

问题是 WebView 在WriteCharacteristic() 运行时不会更新(重绘/重渲染),WebView 重绘/重渲染仅在 WriteCharacteristic() 完成后,意味着进度条 100%。

注意:我已经尝试过runOnUiThread(new Runnable() {});

我的问题是,如何强制mainactivity.webview 立即重绘/重新渲染?

谢谢,

【问题讨论】:

  • 我猜你想在后台线程上运行这个WriteCharacteristic 方法,然后将webvew.loadUrl(...) 发布回主线程。
  • 对,WriteCharacteristicBluetoothLeService类的成员,而这个类是作为服务使用的,mainactivity.bindService(intent, this.mServiceConnection, BIND_AUTO_CREATE);
  • 不过,我现在试试你的建议,在后台线程上运行 WriteCharacteristic
  • 不起作用,我什至避开了所有 BLE 的东西,只需点击 JavaScript -> JS 接口 -> 调用 MainActivity 方法 -> 循环执行进度条更新......仍然只在结束。
  • 我测试了这个主题的所有解决方案stackoverflow.com/questions/22607657/…

标签: javascript java android bluetooth-lowenergy android-webview


【解决方案1】:

正如我在评论中指出的,将长时间运行的进程推送到后台线程,然后在 ui 线程上运行 webview 更新应该可以实现您想要实现的目标。这是我整理的一个简单示例:

package com.example.myapplication

import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.webkit.JavascriptInterface
import android.webkit.WebView
import kotlin.concurrent.thread

class MainActivity : AppCompatActivity() {

    lateinit var webView: WebView

    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        webView = WebView(this)
        webView.settings.javaScriptEnabled = true
        webView.addJavascriptInterface(this, "app")
        setContentView(webView)

        val html =
            """
            <html>
                <head>
                    <script type='text/javascript'>
                        function updateProgress(progress) {
                            let el = document.getElementById('progress');
                            el.innerText = progress;
                        }
                    </script>
                </head>
                <body>                    
                    <p>Value: <span id='progress'>0</span></p>
                    <button onclick='app.startUpdates();'>Start Update</button>
                </body>
            </html>            
            """.trimIndent()

        webView.loadData(html, "text/html", "UTF-8")
    }

    @JavascriptInterface
    fun startUpdates() {
        doSomething()
    }

    private fun doSomething() {
        thread {
            for (i in 1..100) {
                runOnUiThread { webView.evaluateJavascript("updateProgress($i);", null) }
                Thread.sleep(10)
            }
        }
    }

}

【讨论】:

  • 感谢您的评论,但我的项目是在 Java 上的,startUpdates() 必须在 public class MyJSInterface { ... } 上才能使用 webview.addJavascriptInterface()
  • 我相信您能够将其翻译成 Java 并将函数移至您的界面。
  • 对不起,但如果我这样做,我将得到与我已经拥有的相同的 Java 代码。我将尝试创建一个小而完整的示例来轻松识别问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
  • 1970-01-01
  • 2019-06-10
  • 2016-03-31
  • 2015-08-30
  • 2012-01-31
  • 2013-01-30
相关资源
最近更新 更多