Android 使用 Kotlin - 如何使用 HttpUrlConnection

Android with Kotlin - How to use HttpUrlConnection

我正在尝试从 AsyncTask 中的 url 获取数据,但在创建 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();
}

但我不断收到如下所示的错误。

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)
    }
}

Cannot access '': it is 'protected/protected and package/' in 'HttpURLConnection' Cannot create an instance of an abstract class

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

提前致谢。

这里是问题和答案的简化。

为什么会失败?

val connection = HttpURLConnection()
val data = connection.inputStream.bufferedReader().readText()
// ... do something with "data"

有错误:

Kotlin: Cannot access '': it is 'protected/protected and package/' in 'HttpURLConnection'

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

在 Kotlin 中打开此连接并将内容作为字符串读取的最惯用的方法是:

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

阅读完文本或出现异常时,此表单将自动关闭所有内容。如果您想进行自定义阅读:

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

注意: use() 扩展功能将打开和关闭 reader并自动处理关闭错误。

关于disconnect()方法

disconnect 的文档说:

Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances. Calling the close() methods on the InputStream or OutputStream of an HttpURLConnection after a request may free network resources associated with this instance but has no effect on any shared persistent connection. Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.

所以你决定是否要调用它。这是调用断开连接的代码版本:

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

您可以修改您的代码;不要忘记用户可运行线程。

Thread(Runnable {
            try {
                val url = URL("www.android.com")
                val con = url.openConnection() as HttpURLConnection

                val datas = con.inputStream.bufferedReader().readText()

                val json = JSONObject(datas)
                val blockList = json.getJSONObject("blockList")
                val warning = json.get("warnMessage").toString()
                val keys = blockList.keys()
                var permission = HashMap<String, Array<String?>>()

                while (keys.hasNext()) {
                    val key = keys.next()
                    val kods = blockList.getJSONArray(key)

                    val permissonArray = arrayOfNulls<String>(kods.length())
                    for (i in permissonArray.indices) {
                        permissonArray[i] = kods.getString(i)
                    }


                    permission[key] = permissonArray;

                }


            } catch (ex: Exception) {
                Log.d("Exception", ex.toString())
            }
        }).start()

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

下面是帮助程序 object(单例)class,您可以将其用于 GET 和 POST 请求的网络调用。

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

使用上述对象 class 您可以执行 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()

除了使用线程,您还可以使用 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()
        }
    }
}

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

现在要通过你的 onCreate() 中的 AsyncTask NetworkAsyncCall 调用 newtwork 调用,或者你想调用 api 的任何函数,你可以这样写:

注意:上面提到的url是行不通的,你得换成你自己的。

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

对于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()
}

您可以在github here中查看完整代码。 为了更好的解释,你可以查看这个 link.

将 NetworkAsyncCall 用作独立的 class 的优点是您不必再次编写 AsyncTask 代码,只需使用来自不同 [=] 的新对象调用相同的 AsyncTask NetworkAsyncCall 47=],但是有了这个,你必须实现一个监听器接口,你需要在从 api 获得响应后在 onPostExecute() 上进行回调,并将响应返回给 return activity 您必须使用该接口执行回调。