Android与Kotlin - 如何使用HttpUrlConnection

axi*_*tjz 3 android httpurlconnection kotlin

我试图从内部的网址获取数据,AsyncTask但在创建新实例时出现错误HttpUrlConnection.

在Java上有这样的东西

URL url = new URL("http://www.android.com/");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
    InputStream in = new BufferedInputStream(urlConnection.getInputStream());
    readStream(in);
finally {
    urlConnection.disconnect();
}
Run Code Online (Sandbox Code Playgroud)

但我不断收到下面显示的错误.

class GetWeatherTask : AsyncTast<Void, Void, Void>() {

    override fun doInBackground(vararg params: Void?): Void? {
        val httpClient = HttpURLConnection();
        return null
    }
    override fun onPreExecute() {
        super.onPreExecute()
    }
    override fun onPostExecute(result: Void?) {
        super.onPostExecute(result)
    }
}
Run Code Online (Sandbox Code Playgroud)

无法访问'':它是'受保护/ 受保护,而 '/ httpURLConnection'中的包 /'无法创建抽象类的实例

我错过了什么吗?我试图创建一个扩展的类对象HttpUrlConnection并尝试实现该init方法,但我不能

提前致谢.

Jay*_*ard 12

这是问题和答案的简化.

为什么这会失败?

val connection = HttpURLConnection()
val data = connection.inputStream.bufferedReader().readText()
// ... do something with "data"
Run Code Online (Sandbox Code Playgroud)

有错误:

Kotlin:无法访问'':'HttpURLConnection'中的'受保护/ 受保护和包 /'

这会失败,因为您正在构建一个不打算直接构造的类.它意味着由工厂创建,这是URL类openConnection()方法.这也不是原始问题中示例Java代码的直接端口.

在Kotlin中打开此连接并以字符串形式读取内容的最惯用方式是:

val connection = URL("http://www.android.com/").openConnection() as HttpURLConnection
val data = connection.inputStream.bufferedReader().readText()
Run Code Online (Sandbox Code Playgroud)

完成阅读文本或异常后,此表单将自动关闭所有内容.如果你想做自定义阅读:

val connection = URL("http://www.android.com/").openConnection() as HttpURLConnection
connection.inputStream.bufferedReader().use { reader ->
    // ... do something with the reader
}
Run Code Online (Sandbox Code Playgroud)

注: 该use()扩展功能将打开和关闭阅读器和手柄自动关闭上的错误.

关于disconnect()方法

文档disconnect说:

每个HttpURLConnection实例用于发出单个请求,但是与HTTP服务器的基础网络连接可以由其他实例透明地共享.在请求之后调用HttpURLConnection的InputStream或OutputStream上的close()方法可以释放与此实例关联的网络资源,但不会影响任何共享持久连接.如果此时持久连接处于空闲状态,则调用disconnect()方法可能会关闭底层套接字.

所以你决定是否要打电话.以下是调用disconnect的代码版本:

val connection = URL("http://www.android.com/").openConnection() as HttpURLConnection
try {
    val data = connection.inputStream.bufferedReader().use { it.readText() }
    // ... do something with "data"
} finally {
    connection.disconnect()
}
Run Code Online (Sandbox Code Playgroud)


HAX*_*AXM 5

get post执行请求的最简单方法HTTPUrlConnection是创建一个通用帮助程序类,可以从应用程序中的任何位置调用该类来调用 GET 和 POST 请求方法,而无需一次又一次编写相同的代码。

下面是object可用于 GET 和 POST 请求的网络调用的帮助程序 (Singleton) 类。

package com.dewari.ajay.androidnetworkcommunication.network

import org.json.JSONObject
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.IOException
import java.io.InputStreamReader
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL
import java.net.URLEncoder
import javax.net.ssl.HttpsURLConnection


object RequestHandler {

const val GET : String = "GET"
const val POST : String = "POST"

@Throws(IOException::class)
fun requestPOST(r_url: String?, postDataParams: JSONObject): String? {
    val url = URL(r_url)
    val conn: HttpURLConnection = url.openConnection() as HttpURLConnection
    conn.readTimeout = 3000
    conn.connectTimeout = 3000
    conn.requestMethod = POST
    conn.doInput = true
    conn.doOutput = true
    val os: OutputStream = conn.outputStream
    val writer = BufferedWriter(OutputStreamWriter(os, "UTF-8"))
    writer.write(encodeParams(postDataParams))
    writer.flush()
    writer.close()
    os.close()
    val responseCode: Int = conn.responseCode // To Check for 200
    if (responseCode == HttpsURLConnection.HTTP_OK) {
        val `in` = BufferedReader(InputStreamReader(conn.inputStream))
        val sb = StringBuffer("")
        var line: String? = ""
        while (`in`.readLine().also { line = it } != null) {
            sb.append(line)
            break
        }
        `in`.close()
        return sb.toString()
    }
    return null
}

@Throws(IOException::class)
fun requestGET(url: String?): String? {
    val obj = URL(url)
    val con = obj.openConnection() as HttpURLConnection
    con.requestMethod = GET
    val responseCode = con.responseCode
    println("Response Code :: $responseCode")
    return if (responseCode == HttpURLConnection.HTTP_OK) { // connection ok
        val `in` =
            BufferedReader(InputStreamReader(con.inputStream))
        var inputLine: String?
        val response = StringBuffer()
        while (`in`.readLine().also { inputLine = it } != null) {
            response.append(inputLine)
        }
        `in`.close()
        response.toString()
    } else {
        ""
    }
}

@Throws(IOException::class)
private fun encodeParams(params: JSONObject): String? {
    val result = StringBuilder()
    var first = true
    val itr = params.keys()
    while (itr.hasNext()) {
        val key = itr.next()
        val value = params[key]
        if (first) first = false else result.append("&")
        result.append(URLEncoder.encode(key, "UTF-8"))
        result.append("=")
        result.append(URLEncoder.encode(value.toString(), "UTF-8"))
    }
    return result.toString()
  }
}
Run Code Online (Sandbox Code Playgroud)

使用上面的对象类,您可以执行 GET 和 POST 请求,如下所示:

//As this is network call it should be done in a separate thread
                Thread(Runnable {
                RequestHandler.requestGET(url)
                RequestHandler.requestPOST(url, postJSONObject)
            }).start()
Run Code Online (Sandbox Code Playgroud)

除了使用线程之外,您还可以使用 AsyncTask,如下所示:

    class NetworkAsyncCall(private val context: Context, private val url: String, private val requestType:
String, private val postJSONObject: JSONObject = JSONObject()
) : AsyncTask<String?, String?, String?>() {

    override fun doInBackground(vararg p0: String?): String? {
        return when (requestType) {
            RequestHandler.GET -> RequestHandler.requestGET(url)
            RequestHandler.GET -> RequestHandler.requestPOST(url, postJSONObject)
            else -> ""
        }
    }

    override fun onPostExecute(s: String?) {
        if (s != null) {
            Toast.makeText(context, s, Toast.LENGTH_LONG).show()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以将 asyncTask 创建为 Activity 的内部类或单独的独立类。

NetworkAsyncCall现在,要通过您的AsyncTaskonCreate()或任何您想要调用 api 的函数中的AsyncTask 调用 newtwork,您可以编写:

注意:上述网址不起作用,因此您必须将其替换为您自己的网址。

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

    // Change the url with your own GET URL request
    val urlGET = "http://my-json-feed"
    //GET Request
    NetworkAsyncCall(this@MainActivity, urlGET, RequestHandler.GET).execute();

   //       POST Request
   //        doPost()
}
Run Code Online (Sandbox Code Playgroud)

对于 POST 请求,您可以致电:

    private fun doPost() {
    // Change the url with your own POST URL request
    val urlPOST = "http://my-json-feed"
    val postDataParams = JSONObject()
    postDataParams.put("name", "Ajay")
    postDataParams.put("email", "aj****ri@gmail.com")
    postDataParams.put("phone", "+91 78******25")
    NetworkAsyncCall(this@MainActivity, urlPOST, RequestHandler.POST, postDataParams).execute()
}
Run Code Online (Sandbox Code Playgroud)

你可以在这里查看 github 中的完整代码。要获得更好的解释,您可以查看此链接。

使用 NetworkAsyncCall 作为单独的独立类的优点是您不必再次编写 AsyncTask 代码,只需使用NetworkAsyncCall来自不同活动/函数的新对象调用相同的 AsyncTask 即可,但是这样您就必须实现一个侦听器接口从 api 获取响应后需要进行回调onPostExecute(),并将响应返回到必须使用该接口执行回调的活动。