【问题标题】:Ping website URL before loading it in WebView in Android Kotlin在 Android Kotlin 的 WebView 中加载之前 Ping 网站 URL
【发布时间】:2018-11-20 21:51:29
【问题描述】:

在 WebView 中加载网站之前,我想检查 URL 并确保它已加载。如果是,则显示 WebView;如果没有,则显示另一个带有消息的视图。

这个想法是检查网站是否可以加载,并根据响应显示“网站无法加载”屏幕或显示加载了 URL 的 WebView。

我已经检查过连接是否可用,所以不用担心。

需要支持 API 25+。

【问题讨论】:

  • 你的问题被标记为a duplicate of this,所以最好把你的答案贴在那里。在您的回答中,值得解释它与该问题的关系以及它如何解决它(仅代码的答案通常不是很有用)。
  • 不幸的是,这篇文章需要被视为离题,因为它是对另一个问题的回答,而不是一个问题本身。
  • 也许我没有正确解释我最初的问题,但我认为这是主题,因为我的问题有 2 个部分:1) ping 和 2) 在 MainActivity 中使用该答案来显示 WebView。我花了几个小时寻找它,但没有找到任何有用的东西,所以我不得不把它拼凑起来。
  • 我已经编辑了这个,试图让它成为一个更多的问题。这仍然不理想,因为如果您的原始帖子被错误地关闭,则应该重新打开它,而不是创建真正的副本。由于这有一个答案,它很可能会存活下来——亲密的选民不太可能关闭以乐于助人的精神发布的材料。如果您对之前的问题重新投票,那将是理想的选择,如果成功,也许您可​​以将它移到那里(然后删除它)。
  • 在此期间,请接受您的回答,以表明您对解决方案感到满意。

标签: android kotlin


【解决方案1】:

我下面的解决方案是尝试做两件事:

  1. 使用AsyncTask“ping”一个网站,然后

  2. 通过从MainActivity 传递上下文,调用一个函数来显示WebView(这里使用WeakReference 来实现)

class MainActivity : AppCompatActivity() {
private var websiteURL = "https://www.google.com"

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // ...
    webView.webViewClient = WebViewClient()
}

// I called this function after checking that there is Internet connection
private fun connectionResponseFunction(): String {
    return if (isConnected) {
        // *** is connected
        // pass in "this" context from MainActivity
        val downloadData = CheckLink(this)
        downloadData.execute(websiteURL)
    } else {
      // *** not connected
    }
}

private fun showWebView() {
    webView.loadUrl(websiteURL)
}

companion object {
    class CheckLink internal constructor(context: MainActivity) : AsyncTask<String, Void, String>() {
      // Needed if you want to use webView or anything else from MainActivity
        private val activityReference: WeakReference<MainActivity> = WeakReference(context)

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            val activity = activityReference.get()
            if (activity == null || activity.isFinishing) return

            if (result == "success") {
                // URL loaded, show webView
                activity.showWebView()
            } else {
                // URL didn't load
            }
        }

        override fun doInBackground(vararg url: String?): String {
            val linkLoaded = loadLink(url[0])
            if (!linkLoaded) {
                return "failure"
            }
            return "success"
        }

        private fun loadLink(urlPath: String?): Boolean {
            try {
                val url = URL(urlPath)
                val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
                connection.setRequestProperty("Connection", "close")
                connection.connectTimeout = 3000
                connection.connect()

                val response = connection.responseCode

                // 200 for success
                return if (response == 200) {
                    true
                } else {
                    false
                }
            } catch (e: Exception) {
              // Handle exceptions
                when (e) {
                    is MalformedURLException -> "loadLink: Invalid URL ${e.message}"
                    is IOException -> "loadLink: IO Exception reading data: ${e.message}"
                    is SecurityException -> { e.printStackTrace()
                        "loadLink: Security Exception. Needs permission? ${e.message}"
                    }
                    else -> "Unknown error: ${e.message}"
                }
            }
            return false  // Error
        }
    }
}
}

我对 Android 和 Kotlin 还很陌生,所以我愿意接受任何改进它的建议。

我找不到任何适用于 API 25+ 的最新代码。

【讨论】:

    【解决方案2】:

    AsyncTask 的另一个(更短的)替代方案是使用Thread

    Thread {
        val result = isHostAvailable(BuildConfig.BASE_URL)
        runOnUiThread {
            if (result) {
                // do something ...
            }
            else showToast("no connection to server")
        }
    }.start()
    

    fun isHostAvailable(urlPath: String): Boolean {
        try {
            val url = URL(urlPath)
            val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
            connection.setRequestProperty("Connection", "close")
            connection.connectTimeout = 3000
            connection.connect()
    
            return when (connection.responseCode) {
                200, 403 -> true
                else -> false
            }
    
        } catch (e: Exception) {
            when (e) {
                is MalformedURLException -> "loadLink: Invalid URL ${e.message}"
                is IOException -> "loadLink: IO Exception reading data: ${e.message}"
                is SecurityException -> {
                    e.printStackTrace()
                    "loadLink: Security Exception. Needs permission? ${e.message}"
                }
                else -> "Unknown error: ${e.message}"
            }
        }
        return false
    }
    

    【讨论】:

      【解决方案3】:

      看起来 ping 在模拟器上不起作用 (How to Ping External IP from Java Android)...相反,在真实设备上尝试一下,它会起作用:

      val process = Runtime.getRuntime().exec("/system/bin/ping -c 1 $SERVIDOR")
      val pingResult = process .waitFor()
      return pingResult == 0
      

      顺便说一句,@quietbits 给出的答案已经过时了...AsyncTask 类就像 5 年前一样...由于 Android Studio 支持 kotlin,您应该使用协程!代码行差异很大...查看此代码实验室了解更多信息 (https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#0)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-21
        • 2018-06-01
        • 1970-01-01
        • 2016-02-01
        • 2014-07-18
        • 2017-07-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多