【问题标题】:How to WebView.getTitle() from a UI thread?如何从 UI 线程 WebView.getTitle()?
【发布时间】:2012-12-08 15:41:13
【问题描述】:

WebView 的子类中,我曾经在getTitle() 的重写方法中有这一行:

String title = super.getTitle();

它在所有版本的 Android 中运行良好,直到我在 Android 4.1 手机上测试我的应用程序,这在 super.getTitle() 行上给了我这个警告:

12-20 21:38:27.467: W/webview_proxy(2537): java.lang.Throwable: 警告:在线程“WebViewCoreThread”上调用了 WebView 方法。 必须在 UI 线程上调用所有 WebView 方法。未来版本的 WebView 可能不支持在其他线程上使用。

所以,我正在考虑通过runOnUiThread() 来解决这项新法令:

Activity a = this.getActivity();
a.runOnUiThread(new Runnable() {
    public void run() { 
    String title = super.getTitle();
    }
});

但是这段代码甚至无法编译,因为super 不再引用WebView,而是引用Activity

知道如何从 UI 线程super.getTitle() 吗? (具有上述约束,在WebView的子类的getTitle()中)

【问题讨论】:

  • 在哪里您显示的带有Activity a = ... 的sn-p 是?您是否将其放在 MyWebView 类的重写 getTitle() 方法中?
  • 其实上面的匿名Runnable类中的super指向Object:)

标签: android android-webview


【解决方案1】:

Morgan's answer,虽然它可能会修复编译错误,但并不能真正解决这个问题。

首先,它将对getTitle() 的调用更改为不同的线程没有任何作用。这个潜在的问题就是为什么 Android 在运行时给你错误。

你在评论中说

情况是我在WebViewClient.onPageFinished()中调用它,恰好不在UI线程上。

可能是个问题。如果您从 UI 线程启动 Web 请求,那么 onPageFinished() 肯定会在 UI 线程上被回调。您能否解释一下您是如何启动网络请求的,以及为什么您会这样做?绝大多数情况下,您不应该看到在后台调用 onPageFinished(),因此您可能在其他地方遇到问题。

(注意:如果您认为需要在后台调用WebView.loadUrl()以避免阻塞UI,请see this other answer on that issue

如果你真的认为你需要在后台启动网络请求,并且你看到onPageFinished()在后台被调用,你需要小心在UI线程上调用getTitle() .

另外,如果您是从onPageFinished() 方法调用它,则无需使用如下语法:

String title = MyWebView.this.getTitle();

在那个方法中,你被传递了你的 web 视图的实例,所以直接使用它:

public void onPageFinished (WebView view, String url) {
    String title = view.getTitle();
}

但是,正如我所说,这并不能解决线程问题。您需要向我们展示为什么您要尝试在该方法中使用页面标题,但一种安全使用它的方法是这样的:

public void onPageFinished (final WebView view, String url) {
   view.post(new Runnable() {
      public void run() { 
         String title = view.getTitle();
         // do something with title that affects the UI here
      }
   });     
}

注意,我需要在上面的代码中设置view 参数final

【讨论】:

  • +1 是一个非常有教育意义的答案,但是...我从 UI 线程 loadUrl()!那么为什么onPageFinished() 会在非 UI 线程上被调用呢?
  • 首先,我会双重/三次检查它是否真的在后台被调用。在onPageFinished() 中放置一个断点并在调试器中停在那里,然后查看“调试”窗格以查看除 Thread-1 之外的某个线程正在调用该方法。如果它不是主/UI 线程,你能告诉我们调用loadUrl() 的代码吗?另外,您是为了获得onPageFinished() 回调而实现WebViewClient,还是在WebViewClient 实现中做其他事情?将该代码添加到您上面的问题中也可能会有所帮助。谢谢!
  • 我还要补充一点,我最后一个使用 view.post() 的代码 sn-p 应该可以解决问题,即使 onPageFinished() 在后台被调用.但是,我认为最好弄清楚为什么会发生这种情况。因此,该解决方案仍然是一种解决方法
  • 哎哟!你说得对。我犯了一个错误:onPageStarted 和 onPageFinished 都在 UI 线程上被调用。这是另一个线程上的JavascriptInterface 方法(通过view.loadUrl 在onPageFinished 中调用)。自从我查看代码以来已经有一段时间了......我很抱歉从一开始就不准确。至于你的其他问题,我只是实现WebViewClient 来做this。正确的解决方案大概是view.post()view.loadUrl() 让它运行在UI线程上吧?
  • 不用担心。因此,onPageFinished() 中不需要 runOnUiThread()view.post()。但是,我仍然会根据我的中间代码 sn-p (String title = view.getTitle();) 编写代码,因为在这种情况下,使用 MyWebView.this.getTitle() 确实不必要地复杂,而且不太健壮。此外,您在 JavascriptInterface 方法中所做的事情显然仍然存在问题。所以,可能那个方法应该使用post(Runnable)runOnUiThread(Runnable)。见this other question
【解决方案2】:

我没有直接回答您的问题,但是当我遇到类似问题时,我可以建议一种对我有用的解决方法:找到调用调用 String title = super.getTitle(); 的方法的方法并运行 it 来自runOnUiThread()

HTH。

【讨论】:

  • 谢谢 (+1) 但我仍然有兴趣访问 MyWebView 的 super + 它的数据成员。
  • 原来你的解决方案从一开始就是正确的,但它没有提供解释为什么,就像@Nate解释的那样。
【解决方案3】:

直接的解决办法就是这样做

String title = MyWebView.this.getTitle();

而不是

String title = super.getTitle();

话虽如此,了解更多关于您调用它的情况(即,为什么您在后台调用它)会很有趣。我之所以问,是因为我不确定即使在您进行了我提到的代码更改之后,您的方法是否会达到您想要的效果。

【讨论】:

  • 甚至MyWebView.getTitle()
  • @CommonsWare,我想在这种情况下你会得到“无法对非静态方法 getTitle() 进行静态引用”。
  • 有趣——这让我有点吃惊。在任何情况下,您都应该使用 MyWebView.this.getTitle()。祝你好运!
  • 我觉得这让我很吃惊,因为它听起来像一个 UI 风格的回调,而且这些类型的回调通常在 UI 线程上,这样客户端代码(比如你的)就可以轻松地执行主线程操作。
  • 我将尝试查找此功能的 Java 语言规范。可以这样想——代码上下文中有两个“this”对象:“本地”this(匿名 Runnable 子类)和“父”this,即您的 MyWebView。将语法 MyWebView.this 视为告诉 JRE 您要使用哪个语法的一种方式。
【解决方案4】:

要消除此警告,请执行以下操作:

  Handler handler =new Handler();
    handler.post(new Runnable() {

        @Override
        public void run() {
            // TODO Auto-generated method stub
            String URL = "http://www.superlinux.net";

            //Of course the object "webview" is a WebView. 
            //it's better to define it a global variable
            webview.loadUrl(URL);
        }
    });

因此,使用这种方式,因为 webview 是 UI 元素,所以你使用 Handler 对象。处理程序是与创建任何 UI 元素分开运行的某种线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多